Fortran 95/90 allows arrays to be passed as array elements, as array subsections, or as whole arrays referenced by array name. Within Fortran, array elements are ordered in column-major order, meaning the subscripts of the lowest dimensions vary first.
When using arrays between Fortran and another language, differences in element indexing and ordering must be taken into account. You must reference the array elements individually and keep track of them. Fortran and C vary in the way that array elements are indexed. Array indexing is a source-level consideration and involves no difference in the underlying data.
Fortran and C arrays differ in two ways:
The value of the lower array bound is different. By default, Fortran indexes the first element of an array as 1. C and C++ index it as 0. Fortran subscripts should therefore be one higher. (Fortran also provides the option of specifying another integer lower bound.)
In arrays of more than one dimension, Fortran varies the left-most index the fastest, while C varies the right-most index the fastest. These are sometimes called column-major order and row-major order, respectively.
In C, the first four elements of an array declared as X are:
X X X X
In Fortran, the first four elements are:
X(1,1) X(2,1) X(3,1) X(1,2)
The order of indexing extends to any number of dimensions you declare. For example, the C declaration:
is equivalent to the Fortran declaration:
INTEGER arr1( 20, 15, 10, 2 )
The constants used in a C array declaration represent extents, not upper bounds as they do in other languages. Therefore, the last element in the C array declared as int arr is arr, not arr.
The following table shows equivalencies for array declarations.
Equivalent Array Declarations for Different Languages
Array Reference from Fortran
DIMENSION x(i, k)
type x[ k ] [ i ]
x( i -1, k -1)
For cases where Fortran 95/90 needs to keep track of more than a pointer memory address, the Intel Fortran Compiler uses an array descriptor, which stores the details of how an array is organized.
When using an explicit interface (by association or procedure interface block), Intel Fortran generates a descriptor for the following types of array arguments:
Pointers to arrays (array pointers)
Certain data structure arguments do not use a descriptor, even when an appropriate explicit interface is provided. For example, explicit-shape and assumed-size arrays do not use a descriptor. In contrast, array pointers and allocatable arrays use descriptors regardless of whether they are used as arguments.
When calling between Intel Fortran and a non-Fortran language (such as C), using an implicit interface allows the array argument to be passed without an Intel Fortran descriptor. However, for cases where the called routine needs the information in the Intel Fortran descriptor, declare the routine with an explicit interface and specify the dummy array as either an assumed-shape array or with the pointer attribute.
You can associate a Fortran 95/90 pointer with any piece of memory, organized in any way desired (so long as it is "rectangular" in terms of array bounds). You can also pass Fortran 95/90 pointers to other languages, such as C, and have the other language correctly interpret the descriptor to obtain the information it needs.
However, using array descriptors can increase the opportunity for errors and the corresponding code is not portable. In particular, be aware of the following:
If the descriptor is not defined correctly, the program may access the wrong memory address, possibly causing a General Protection Fault.
Array descriptor formats are specific to each Fortran compiler. Code that uses array descriptors is not portable to other compilers or platforms. For example, the current Intel Fortran array descriptor format differs from the array descriptor format for Intel Fortran 7.0.
The array descriptor format may change in the future.
The components of the current Intel Fortran array descriptor on IA-32 systems are as follows:
The first longword (bytes 0 to 3) contains the base address. The base address plus the offset defines the first memory location (start) of the array.
The second longword (bytes 4 to 7) contains the size of a single element of the array.
The third longword (bytes 8 to 11) contains the offset. The offset is added to the base address to define the start of the array.
The fourth longword (bytes 12 to 15) contains the low-order bit set if the array has been defined (storage allocated). Other bits may also be set by the compiler within this longword, for example, to indicate a contiguous array.
The fifth longword (bytes 16 to 19) contains the number of dimensions (rank) of the array.
The sixth longword (bytes 20 to 23) is reserved.
The remaining longwords (bytes 24 up to 107) contain information about each dimension (up to seven). Each dimension is described by three additional longwords:
The number of elements (extent)
The distance between the starting address of two successive elements in this dimension, in bytes.
The lower bound
An array of rank one requires three additional longwords for a total of nine longwords (6 + 3*1) and ends at byte 35. An array of rank seven is described in a total of 27 longwords (6 + 3*7) and ends at byte 107.
For example, consider the following declaration:
integer,target :: a(10,10) integer,pointer :: p(:,:) p => a(9:1:-2,1:9:3) call f(p).
The descriptor for actual argument p would contain the following values:
The first longword (bytes 0 to 3) contain the base address (assigned at run-time).
The second longword (bytes 4 to 7) is set to 4 (size of a single element).
The third longword (bytes 8 to 11) contain the offset (assigned at run-time).
The fourth longword (bytes 12 to 15) contains 1 (low bit is set).
The fifth longword (bytes 16 to 19) contains 2 (rank).
The sixth longword is reserved.
The seventh, eighth, and ninth longwords (bytes 24 to 35) contain information for the first dimension, as follows:
-8 (distance between elements)
9 (the lower bound)
For the second dimension, the tenth, eleventh, and twelfth longwords (bytes 36 to 47) contain:
120 (distance between elements)
1 (the lower bound)
Byte 47 is the last byte for this example.
The format for the descriptor on Itanium-based systems is identical to that on IA-32 systems, except that all fields are 8-bytes long, instead of 4-bytes.