next up previous 211
Next: Enlarging integer type in C
Up: Modifications to code
Previous: Pointer references in Fortran 77


Enlarging integer type in Fortran 77

In Fortran 77 there is no (even slightly) portable way of declaring an integer to be of a configurable length. Therefore all variables currently declared as `INTEGER' should be changed instead to type `INTEGER*8'. This is not standard Fortran 77, but it is widely understood by compilers. This should not be interpreted (by a human) as an indication that exactly eight bytes are required, but as an indication that the variable in question needs to be long enough to hold a large number. At compile time, typically on 64-bit systems the code will be compiled as it stands, while on 32-bit systems a simple sed command or similar can preprocess the source code before it is fed to the compiler, under makefile control (see section 3.4).

Having done this, the following issues may need to be addressed.

External libraries

In Fortran, the actual arguments used in a subroutine/function call must be of the same type as the formal arguments declared in the routine itself, since arguments are passed by address. Thus if you change the type of integers passed to a subroutine, you have to change the type of the integers declared in the subroutine too. It is therefore necessary either to convert any called subroutines to using the new integer type (at least as far as their arguments go), or to ensure that any calls to these routines use variables of the old integer type. Thus a package can only be successfully converted to large integers and built once all the libraries against which it links have been similarly converted. The Starlink libraries will therefore have to be done before applications packages. If a program uses an external library which is not part of the USSC, then either the library will have to be converted in the same way, or the affected calls will have to be written using variables specially declared as the normal INTEGER type.
Literal integer constants as arguments

If there are any calls to functions or subroutines in the converted code which have literal integer constants as actual arguments, these will need to be replaced with expressions of the right type. There is no way of specifying the length of a literal integer constant in Fortran, so you must ensure that the expression has the correct type in some other way. The recommended method for doing this is to use a variable for the purpose, which may be assigned using a PARAMETER statement. Thus
      CALL SUB( 5, STATUS )
must be changed to something like
      INTEGER * 8 INT__5
      PARAMETER ( INT__5 = 5 )
        ...
      CALL SUB( INT__5, STATUS )
Other methods of getting around this are possible, for instance using statement functions. The include files EXT_PAR, which contains a set of predefined integer constants, and EXT_DEC and EXT_DEF, which define statement functions in the same way as the PRIMDAT package, are provided with the EXTREME package by way of example of alternative strategies.
Intrinsic functions

Calls to standard Fortran intrinsic functions should take care of themselves, as long as the generic name is used rather than the specific one (e.g. you should use ABS instead of IABS), since they adapt themselves automatically to the type of their argument. Use of generic names is generally good practice anyway; the only time it is necessary to supply the specific name is when passing an intrinsic function itself as an actual argument to a procedure, which is pretty rare. The only intrinsic functions in standard Fortran 77 which have INTEGER-specific names are IABS, ISIGN, IDIM, MAX0, AMAX0, MIN0 and AMIN0.

There are some non-standard intrinsic functions which require INTEGER arguments, and will cause trouble if they have INTEGER*8 arguments. These are mostly system-specific ones, such as GETARG, and are likely only to be used in fairly low level code.

A related problem is using a call to an intrinsic function with an integer return type as an actual argument to a function. Since for most functions the return type is the same as the argument, this will, again, take care of itself. However, for the few intrinsic functions which return integer regardless of the type of the argument (LEN, INDEX), the return value will have to be converted to the correct type as if it were an integer literal, by assigning to an intermediate variable or using a statement function.

Storage association

The Fortran 77 standard does not state how much storage is used by an INTEGER, but does state that it should be the same amount as that used by REALs and LOGICALs. Converting all INTEGERs to INTEGER*8s will normally have the effect that this is no longer the case. Thus code which relies on this, for instance by using COMMON blocks or EQUIVALENCE statements to address the same memory as both INTEGER and REAL, will break. Such practices are, as you might expect, deprecated by the Starlink Application Programming Standard, but there may be instances of them lurking about.

Similarly, code which makes the assumption that four elements of a CHARACTER array correspond to each INTEGER will need changing.

Storage alignment

The compiler documentation indicates that 64-bit data types on Sun and Alpha systems should be aligned on 64-bit boundaries for performance reasons. Normally this is taken care of automatically by the compiler, but in COMMON blocks (or EQUIVALENCE?) the address of a variable is determined by the source code, so that the compiler is not free to move it around (the start of a COMMON block is always aligned to the largest boundary, 64 bits). Thus the following code:
      REAL        XX, YY
      INTEGER * 8 IX, IY
      COMMON /BLOCK/ XX, IX, YY, IY
which would align everything (happily) on 32-bit boundaries if IX, IY were INTEGER*4s, will be forced to align the 64-bit IX on a 32-bit boundary. The compilers will warn about this behaviour. I believe that the result will be slower, rather than incorrect, executables, but such occurrences should ideally be fixed.
IMPLICIT variable declarations

It is highly desirable in Fortran, and usual in Starlink code, to use the ``IMPLICIT NONE'' declaration, so that all variables have to be explicitly declared before use. If this is not done, and integer variables are used without explicit declaration, they will not be converted to INTEGER*8. It would be possible to fix this by redeclaring IMPLICIT INTEGER statements as IMPLICIT INTEGER*8 and/or adding an IMPLICIT INTEGER*8 (I-N), but to make the job easier for the makefile in editing the source code, it is better to place an ``IMPLICIT NONE'' statement in every source code module, and make explicit INTEGER*8 declarations for all integers.
I/O return values

A few Fortran I/O statements have specifiers which require the name of an INTEGER variable. In standard Fortran 77 these are IOSTAT in all I/O statements, and NUMBER, RECL and NEXTREC in the INQUIRE statement. Particular compilers often provide a whole lot more, but these should hopefully not be much used in Starlink code. So there may be a problem with a statement like
      CLOSE( UNIT = 99, IOSTAT = STVAL )
if the variable STVAL is now declared INTEGER*8 rather than INTEGER. Of the supported systems, Tru64 and Solaris seem to handle INTEGER*8 variables used for this purpose without complaint. Linux with g77 0.5.24 may fail to compile although (a) it seems to be OK if you compile with -O, and (b) this is reportedly fixed at g77 0.5.25. So it's probably all right to leave these cases.

The program frepint, and the corresponding driver script do-frepint, is provided for changing INTEGER declarations to INTEGER*8. Details of which of the above constructs it fixes, and which it warns about, are given in the appendix.



next up previous 211
Next: Enlarging integer type in C
Up: Modifications to code
Previous: Pointer references in Fortran 77


Starlink System Note 73
Mark Taylor
13 August 2001
E-mail:ussc@star.rl.ac.uk

Copyright © 2001 Council for the Central Laboratory of the Research Councils