I have a C library that declares several long
variables in structs. I usually treat them as integer(kind=c_long)
in Fortran, but that caused unexpected issues in a specific more complex program. My Fortran code ran correctly in a 32-bit system, and didn't even compile in a 64-bit system. The reason is too complicated to explain here and it doesn't really matter for the purpose of the question, but it comes down to the fact c_long
is not the same in 32- and 64-bit systems. At least in gfortran, c_long
is 4 bytes in 32-bit and 8 bytes in 64-bit. In fact, c_long = c_int = 4
in 32-bit, while in 64-bit it is c_long = c_double = 8
.
Now, in this particular C library long
integers are just used for char
variables, and the maximum one used is $FFFFFF, well beyond the limit of c_long
integers in 32-bit systems, since huge(1_c_long)=$7FFFFFFF
in 32-bit. So I have several ways to get rid of the problem, but I still wonder... why it has to be that way in the first place? For example, c_double
is the same both in 32- and 64-bit systems (as it should); same for c_int
, it is the same no matter what. Why c_long
is different? It took me several hours to figure out what's going on in a complex program just because of this.
CodePudding user response:
There is no universal length of long
(or even of int
). Various systems and compilers use one of the common data models (Wikipedia), which use either 32 bits and 64 bits for int
, long
, long long
and pointers.
Fortran specifies the iso_c_binding
types using the concept of a companion processor. That means that the Fortran compiler in its specific configuration (in a specific operating system) use the types to be compatible with a specific C compiler with some specific configuration on a specific operating system.
Notably, Microsoft and MinGW C compilers on Microsoft Windows use the LLP64 model. Compilers on Linux and other Unixes normally use the LP64 data model. Hence the size of long
differs.
It is hard to say anything more for your situation without specific details (compilers, OS). But the sizes are not universal and only valid for a specific compiler on a specific OS that the Fortran compiler regards as the companion processor.
CodePudding user response:
The following small program reveals what's going on:
#include <limits.h>
#include <stdio.h>
int main() {
printf(" Maximum int: %X (%u bytes)\n",INT_MAX,sizeof(int));
printf("Maximum long: %lX (%u bytes)\n",LONG_MAX,sizeof(long));
return 0;
}
With gcc 11.2 on a 32-bit GNU/Linux system this gives:
Maximum int: 7FFFFFFF (4 bytes)
Maximum long: 7FFFFFFF (4 bytes)
And on a 64-bit system it gives:
Maximum int: 7FFFFFFF (4 bytes)
Maximum long: 7FFFFFFFFFFFFFFF (8 bytes)
Therefore, Fortran did nothing wrong. The problem (or however one might want to call it) comes from the C side. There is no standard - or at least not one standard - and C doesn't have something similar to Fortran's fixed-size kinds (which isn't perfect, but at least makes things somewhat less confusing). long
integers are just different in C, depending on your operating system. So iso_c_binding
had no choice but to provide different c_long
types as well.
Lesson learned: Never ever assume anything. There ain't such a thing as a single, universal c_long
and, as Vladimir F pointed out, there ain't such a thing as a single universal c_int
(or whatever else) either.