Module for dealing with unsigned integers in standard Fortran

In contrast to C, no Fortran standard does provide unsigned data types (although there are some vendor extensions). This can cause problem when interfacing C functions that require unsigned arguments. For example the components of RGB-values or parts of IPv4 adresses are often expressed as unsigned 8-bit integers.

In principle it is possible to pass signed integers with the same bit pattern as the unsigned value one wants to pass (For example, both an unsigned 8-bit integer with the value 128 and a signed integer with the value -128 have the same bit pattern (binary: 1000 0000) if the Two’s complement is used as is it the case for most systems. This may, however, lead to code that is difficult to read and maintain.

I have written a module that takes the numerical values of larger integer types (i.e. types where more bits are used to store the data) and storeds them into smaller types in a way that the bit pattern corresponds to a unsigned (C-type) variable…

For example the function call int16_to_unit8(+128) stores returns 128 (The bit pattern of a +128 in an unsigned variable is equal to the bit pattern of -128 in a signed variable, 1000 0000 in binary notation).

It is also possible to store the numerical value of an integer whose bit pattern is interpreted as unsigned in a “larger” integer variable uint8_to_int16(-128_int8) .eq. +128_int16.

(The functions assume that the Two’s complement is used and the endianness of the data to be converted is the same.)

My module (along with some test programs) can be found at

.
However, the code is not very polished and it is (apart from learning) probably not useful to re-“invent” the same thing for the 1000-th time.
So I’d like to know whether there is a well-known and posibly more efficient set of functions for this task that works with standard fortran and requires no vendor extension.

4 Likes

Not an answer to your question, but I have read some materials saying that in most circumstances unsigned integers are best to be avoided in C++:

The bottom line of one of those articles is:

Avoid using unsigned ints in C and C++ unless you’re dealing with raw memory contents or performing bit manipulations like shifting or masking.

Now to Fortran, in case you need to fill an integer with a binary pattern you can use boz constants. More about them in the great blog post by @sblionel: Doctor Fortran in "We're All BOZos on This Bus" - Doctor Fortran

As an example you could do:

use iso_fortran_env, only: int8
integer(int8) :: a, b

a = int(128,int8)  ! requires -fno-range-check
! or
a = 128_int8       ! requires -fno-range-check
! or
b = int(b'10000000',int8)

print *, a, b
end

With recent gfortran versions you might need to use the flag -fno-range-check:

Disable range checking of input values during integer READ operations. For example, GNU Fortran will give an error if an input value is outside of the relevant range of [ -HUGE() : HUGE() ]. In other words, with INTEGER (kind=4) :: i , attempting to read -2147483648 will give an error unless -fno-range-check is given.

6 Likes

There was a BITS data type proposed for Fortran 2008 that effectively solved the problems associated with sign-independent bit patterns. It was dropped as part of the compromise that F2008 was “too big”, but the edits for it were included in J3 file 07-007r1.pdf if you want to look at the details.

1 Like

Thank you @Jweber for joining the Forum and for posting about your library. Welcome!

See also these two proposals in the “incubator” repository and the discussion therein:

1 Like

Thanks a lot for your feedback.

1 Like

Thanks a lot for your feedback and the links to additional
information concerning the topic.

I am currently trying to learn how to wrap C functions in Fortran
(Currently for fun only as I am no longer develop scientific codes
after leaving academia.) and have by no mean experience in mixed-language
programing.
When looking at some C libraries I was wondering what happens, if a C library uses
unsiged types like unsigned int or size_t.

Even if unsigned types have problems as the sources you have provided
have pointed out, they are actually used quite frequently to describe natural numbers
even in important libraries like the C standard library or the UNIX socket library.

In many situations it will be better to write some additional wrapper code in C to provide an interface that better matches the programming practices (and idiosyncrasies) of Fortran.

As an idea you could define an interoperable C routine to return a scalar or array of integer bit patterns you need. However in the case of signed and unsigned conversion, quoting,

there is no fully C-compliant way to do this because casting between signed/unsigned for values out of range is implementation-defined. But this will still work in most cases:

unsigned int x = 65529;
int y = (short) x;      //  If short is a 16-bit integer.

or alternatively:

unsigned int x = 65529;
int y = (int16_t) x;    //  This is defined in <stdint.h>

To access such a “global” C variable in your Fortran program, you can use a declaration like:

integer(c_int), bind(c,name="y") :: y

Depending on how you want to use bit patterns you could also consider using the new Fortran stdlib bitset_type or the maturer C++ std::bitset.

2 Likes

Actually your suggestions lead to much faster code than invoking my library functions (> 2 orders of magnitudes for gfortran 9.3) for the conversion large signed integer ==> small unsigned integer.
So I guess the funsignedwrapper module should not be used when performance is a concern.

Still the the module may be used for the conversion
small unsigned integer ==> large signed integer.

I put together a brief intro to interfacing C and Fortran on YouTube. You could give that a look. Let me know if it’s helpful.

1 Like

Thanks a lot for the really helpful introduction to C-Fortran intertopability!

@Jweber,

Welcome to the forum.

Can you please provide (or point to) an example or two with C functions where you have such a need?

1 Like

@FortranFan

I currently don’t really work on a concrete problem (yet).
Actually, I used Fortran during my PhD (numerical astrophysics)
and postdoc time.
While I have left academia almost two years ago and numerical
programming is no longer a part of my job, I am still interested in the
programming language Fortran on a hobby basis.

I liked the language, but on the other hand have used a rather
Fortran-90 style language back then.
Now my current job we use an object-oriented programming language
and make strong use of supporting tools like debuggers etc. that in retrospect
would have made my work easier back then.

So I’d like understand the usage of modern concepts/techniques in the context of
Fortran programing, but as mentioned before it is currently just for fun.

I asked my question questions and wrote my (not-so-efficient…) module because
I really think that interopability and programers that understand the corresponding concepts
and problems are very important for the future of Fortran to prevent its niche from becoming
too small.

By the way, I really appreciate your helpful answers and your friendliness towards newbies
in the forum and your efforts to enhance the usability of Fortran for the presence and future.

3 Likes