Developer Guide and Reference

ID 767251
Date 10/31/2024
Public
Document Table of Contents

Handle Fortran Array Descriptors

For cases where Standard Fortran 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), the compiler generates a descriptor for the following types of array arguments:

  • Fortran array pointers

  • Assumed-shape arrays

  • Allocatable arrays

  • Coarrays

  • Class objects

Certain types of 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 C/C++, use an implicit interface, which 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.

NOTE:

The information in the remainder of this section is specific to Intel® Fortran, and subject to change in future releases. For information on how to interoperate with C and array descriptors in a portable and standard fashion, see C Structures, Typedefs, and Macros for Interoperability.

You can associate a Fortran array pointer with any piece of memory, organized in any way desired (as long as it is "rectangular" in terms of array bounds). You can also pass Fortran array pointers to the C language, and have it correctly interpret the descriptor to obtain the information it needs.

The downside to using array descriptors is that it can increase the opportunity for errors. Additionally, the corresponding code is not portable. Specifically:

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

  • 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 are as follows:

  • Bytes 0 to 7 contain the base address.

  • Bytes 8 to 15 contain the size of a single element of the array.

  • Bytes 16 to 23 are reserved and should not be explicitly set.

  • Bytes 24 to 31 contain 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.

    • bit 8 (0x80): set if the array pointed to is ALLOCATABLE.

    • Other bits are reserved.

  • Bytes 32 to 39 contain the number of dimensions (rank) of the array.

  • Bytes 40 to 47 are reserved and should not be explicitly set.

  • The remaining bytes contain information about each dimension (up to 31). Each dimension is described by a set of three 8-byte entities:

    • 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 8-byte entities for a total of nine 8-byte entities (6 + 3*1) and ends at byte 71. An array of rank seven is described in a total of twenty-seven 8-byte entities (6 + 3*7) and ends at byte 215. 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:

  • Bytes 0 to 7 contain the base address (assigned at runtime).

  • Bytes 8 to 15 are set to 4 (size of a single element).

  • Bytes 16 to 23 are reserved.

  • Bytes 24 to 31 contain 3 (array is defined and deallocation is not allowed).

  • Bytes 32 to 39 contain 2 (rank).

  • Bytes 40 to 47 are reserved.

  • Bytes 48 to 71 contain information for the first dimension, as follows:

    • 5 (extent).

    • -8 (distance between elements).

    • 9 (the lower bound).

  • For the second dimension, bytes 72 to 95 contain:

    • 3 (extent).

    • 120 (distance between elements).

    • 1 (the lower bound).

  • Byte 95 is the last byte for this example.