Integer8

From Diracwiki

Jump to: navigation, search

Contents


Introduction

What happens when a subroutine expecting an integer*4 argument is called with a integer*8 argument?

The answer depends on the hardware and software platform, and unfortunately errors can often be difficult to detect. To understand this look at the memory layout of the number 12345 stored in integer*4 and integer*8 variables, on an regular Intel CPU (x86):

39 30  0  0 
39 30  0  0  0  0  0  0

The first line shows the four bytes of the integer*4, in the order they are stored in memory on this particular machine. The second line shows the eight bytes of the integer*8 representing the same number. As you can see the start of the integer*8 is the same as the integer*4 (on this machine!).

Similarly the number -1 is stored as

ff ff ff ff 
ff ff ff ff ff ff ff ff 

Again the first four bytes are the same.

Testing program

To understand what can go wrong take the FORTRAN77 example

subroutine f(x)
integer*4 x
print *, x
x = 12345
end

program p
integer*8 y
y = -1
call f(y)
print *,y
end

Since Fortran arguments are passed by reference, the subroutine f will get a pointer to the variable y. From the example above we know that the first four bytes of an integer*8 "-1" are the same as those of a integer*4 "-1".

Therefore the number "-1" will be printed from f(), after which things go bad. This is what happens:

First we set y = -1:

y = ff ff ff ff  ff ff ff ff

Then f(y) is called. The variable x will reference "y", but will only use the first four bytes:

x = ff ff ff ff (ff ff ff ff)

This x is printed as "-1". The we set x = 12345, note that only the first four bytes are modified!

x = 39 30 00 00 (ff ff ff ff)

When f() returns y will have the value

y = 39 30 00 00  ff ff ff ff

Which will be printed as -4294954951.

This is just one example of how things can go wrong, and why things can often work by "chance".

Note that this is very platform dependent, on a big-endian CPU the above example would not work at all. Always make sure to use the correct integer type in arguments, and link to correct versions of external libraries.

Notes

  • The above example would work "correctly" if y was set to 0 on entry. If you find that you need to initialize intent(out) variables to 0 you may have an integer size mismatch.
  • Passing integer arrays of the wrong size gives even more obvious bugs.
  • Problems also appear if you pass integer*4 variables to a subroutine expecting integer*8.

Integer*4/8 type safe programs

FORTRAN90 compilers, which are checking also agreement of data types, should catch most of their incompatibilities in the code.

Though this is not the case of the Fortran77 example given above, one can rewrite this small piece of the code into a proper 'Fortran90 checking form' by utilizing module.

Program "test_f90.F90" (don't forget big F in the suffix when applying preprocessor statements!) shall have this form:

 module pass_integer
 contains
 subroutine f(x)
#if defined (F_INT4)
 integer(kind=4), intent(inout) :: x ! F90 compiler gives error !
#else
 integer(kind=8), intent(inout) :: x ! F90 compiler passed
#endif
 print *, x
 x = 12345
 end subroutine f
 end module pass_integer
 program p
 use pass_integer
 integer (kind=8) :: y
 y = -1
 call f(y)
 print *,y
 end program p

Typing

gfortran -DF_INT4 test_f90.F90 

gives error of "Type/rank mismatch in argument 'x'" while

gfortran test_f90.F90

compiles with the proper integer kind.

Examples of parallel compiling

add openmpi f77/f90 examples .

Personal tools