# Handling Arrays and Fortran Array Descriptors

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. 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[3][3] are:

`  X[0][0] X[0][1] X[0][2] X[1][0]`

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:

`  int arr1[2][10][15][20];`

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[5][5] is arr[4][4], not arr[5][5].

The following table shows equivalencies for array declarations.

Language

Array Declaration

Array Reference from Fortran

Fortran

DIMENSION x(i, k)

-or-

type x(i, k)

x(i, k)

C/C++

type x[ k ] [ i ]

x( i -1, k -1)

## Handling Arrays in Visual Basic and MASM

The following information on Visual Basic and MASM applies to Windows operating systems only.

To pass an array from Visual Basic to Fortran, pass the first element of the array. By default, Visual Basic passes variables by reference, so passing the first element of the array will give Fortran the starting location of the array, just as Fortran expects. Visual Basic indexes the first array element as 0 by default, while Fortran by default indexes it as 1. Visual Basic indexing can be set to start with 1 using the statement:

`  Option Base 1`

Alternatively, in the array declaration in either language you can set the array lower bound to any integer in the range -32,768 to 32,767. For example:

``` ' In Basic
Declare Sub FORTARRAY Lib "fortarr.dll" (Barray as Single)
DIM barray (1 to 3, 1 to 7) As Single
Call FORTARRAY(barray (1,1))
! In Fortran
Subroutine FORTARRAY(arr)
REAL arr(1:3,1:7)```

In MASM, arrays are one-dimensional and array elements must be referenced byte-by-byte. The assembler stores elements of the array consecutively in memory, with the first address referenced by the array name. You then access each element relative to the first, skipping the total number of bytes of the previous elements. For example:

``` xarray    REAL4     1.1, 2.2, 3.3, 4.4 ; initializes
; a four element array with
; each element 4 bytes```

Referencing xarray in MASM refers to the first element, the element containing 1.1. To refer to the second element, you must refer to the element 4 bytes beyond the first with xarray[4] or xarray+4. Similarly:

``` yarray     BYTE      256 DUP     ; establishes a
; 256 byte buffer, no initialization
zarray SWORD 100 DUP(0) ; establishes 100
; two-byte elements, initialized to 0```

## Intel Fortran Array Descriptor Format

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)

• Assumed-shape arrays

• Allocatable array

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 notportable 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.

• If the descriptor was built by the compiler, it cannot be modified by the user. Changing fields of existing descriptors is illegal.

The components of the current Intel Fortran array descriptor on systems using IA-32 architecture 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 A0 offset. The A0 offset is added to the base address to calculate the address for the element with all indices zero, even if that is outside the bounds of the actual array. This is helpful in computing array element addresses.

• The fourth longword (bytes 12 to 15) contains a set of flags used to store information about the array. This includes:

• bit 1 (0x01): array is defined -- set if the array has been defined (storage allocated)

• bit 2 (0x02): no deallocation allowed -- set if the array pointed to cannot be deallocated (that is, it is an explicit array target)

• bit 3 (0x04): array is contiguous -- set if the array pointed to is a contiguous whole array or slice.

• 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 and should not be explicitly set.

• The remaining longwords (bytes 24 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) contains 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) contains the A0 offset of -112.

• The fourth longword (bytes 12 to 15) contains 3 (array is defined and deallocation is not allowed).

• The fifth longword (bytes 16 to 19) contains 2 (rank).

• The sixth longword (bytes 20-23) is reserved.

• The seventh, eighth, and ninth longwords (bytes 24 to 35) contain information for the first dimension, as follows:

• 5 (extent)

• -8 (distance between elements)

• 9 (the lower bound)

• For the second dimension, the tenth, eleventh, and twelfth longwords (bytes 36 to 47) contain:

• 3 (extent)

• 120 (distance between elements)

• 1 (the lower bound)

• Byte 47 is the last byte for this example.

### Note

The format for the descriptor on systems using Intel® 64 architecture is identical to that on systems using IA-32 architecture, except that all fields are 8-bytes long, instead of 4-bytes.

## Handling Large Arrays

When compiling a program with an array greater than 2GB on systems using Intel® 64 architecture and running Linux OS, you may need to specify certain compiler options. Specifically, you may need to use either the -mcmodel=medium or -mcmodel=large compiler option and also the -shared-intel option. For more information, see Specifying Memory Models to use with Systems Based on Intel® 64 Architecture.