:orphan:
 

Working with integer*8 variables
====================================

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 illustrated situation 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.