Cray pointers (The GNU Fortran Compiler)

#### 5.1.16 Cray pointers ¶

Cray pointers are part of a nonstandard extension that provides a C-like pointer in Fortran. This is accomplished through a pair of variables: an integer “pointer” that holds a memory address, and a “pointee” that is used to dereference the pointer.

Pointer/pointee pairs are declared in statements of the form:

            pointer ( <pointer> , <pointee> )

or,

            pointer ( <pointer1> , <pointee1> ), ( <pointer2> , <pointee2> ), ...

The pointer is an integer that is intended to hold a memory address. The pointee may be an array or scalar. If an assumed-size array is permitted within the scoping unit, a pointee can be an assumed-size array. That is, the last dimension may be left unspecified by using a `*` in place of a value. A pointee cannot be an assumed shape array. No space is allocated for the pointee.

The pointee may have its type declared before or after the pointer statement, and its array specification (if any) may be declared before, during, or after the pointer statement. The pointer may be declared as an integer prior to the pointer statement. However, some machines have default integer sizes that are different than the size of a pointer, and so the following code is not portable:

            integer ipt
            pointer (ipt, iarr)

If a pointer is declared with a kind that is too small, the compiler issues a warning; the resulting binary will probably not work correctly, because the memory addresses stored in the pointers may be truncated. It is safer to omit the first line of the above example; if explicit declaration of `ipt`’s type is omitted, then the compiler ensures that `ipt` is an integer variable large enough to hold a pointer.

Pointer arithmetic is valid with Cray pointers, but it is not the same as C pointer arithmetic. Cray pointers are just ordinary integers, so the user is responsible for determining how many bytes to add to a pointer in order to increment it. Consider the following example:

            real target(10)
            real pointee(10)
            pointer (ipt, pointee)
            ipt = loc (target)
            ipt = ipt + 1

The last statement does not set `ipt` to the address of `target(1)`, as it would in C pointer arithmetic. Adding `1` to `ipt` just adds one byte to the address stored in `ipt`.

Any expression involving the pointee is translated to use the value stored in the pointer as the base address.

To get the address of elements, this extension provides an intrinsic function `LOC()`. The `LOC()` function is equivalent to the `&` operator in C, except the address is cast to an integer type:

            real ar(10)
            pointer(ipt, arpte(10))
            real arpte
            ipt = loc(ar)  ! Makes arpte is an alias for ar
            arpte(1) = 1.0 ! Sets ar(1) to 1.0

The pointer can also be set by a call to the `MALLOC` intrinsic (see `MALLOC` — Allocate dynamic memory).

Cray pointees often are used to alias an existing variable. For example:

            integer target(10)
            integer iarr(10)
            pointer (ipt, iarr)
            ipt = loc(target)

As long as `ipt` remains unchanged, `iarr` is now an alias for `target`. The optimizer, however, does not detect this aliasing, so it is unsafe to use `iarr` and `target` simultaneously. Using a pointee in any way that violates the Fortran aliasing rules or assumptions is invalid. It is the user’s responsibility to avoid doing this; the compiler works under the assumption that no such aliasing occurs.

Cray pointers work correctly when there is no aliasing (i.e., when they are used to access a dynamically allocated block of memory), and also in any routine where a pointee is used, but any variable with which it shares storage is not used. Code that violates these rules may not run as the user intends. This is not a bug in the optimizer; any code that violates the aliasing rules is invalid. (Note that this is not unique to GNU Fortran; any Fortran compiler that supports Cray pointers “incorrectly” optimizes code with invalid aliasing.)

There are a number of restrictions on the attributes that can be applied to Cray pointers and pointees. Pointees may not have the `ALLOCATABLE`, `INTENT`, `OPTIONAL`, `DUMMY`, `TARGET`, `INTRINSIC`, or `POINTER` attributes. Pointers may not have the `DIMENSION`, `POINTER`, `TARGET`, `ALLOCATABLE`, `EXTERNAL`, or `INTRINSIC` attributes, nor may they be function results. Pointees may not occur in more than one pointer statement. A pointee cannot be a pointer. Pointees cannot occur in equivalence, common, or data statements.

A Cray pointer may also point to a function or a subroutine. For example, the following excerpt is valid:

      implicit none
      external sub
      pointer (subptr,subpte)
      external subpte
      subptr = loc(sub)
      call subpte()
      [...]
      subroutine sub
      [...]
      end subroutine sub

A pointer may be modified during the course of a program, and this changes the location to which the pointee refers. However, when pointees are passed as arguments, they are treated as ordinary variables in the invoked function. Subsequent changes to the pointer do not change the base address of the array that was passed.