The __far type qualifier (C only)

When the METAL option is in effect, you can use the __far keyword to qualify a pointer type so that it can access additional data spaces in access-register (AR) mode. The upper half of the pointer contains the access-list-entry token (ALET), which identifies the secondary virtual address space you want to access. The lower half the pointer is the offset within the secondary virtual address space. The size of a __far-qualified pointer is increased to 8 bytes in 31-bit mode and 16 bytes in 64-bit mode. In 31-bit mode, the upper 4 bytes contain the ALET, and the lower 4 bytes is the address within the data space. In 64-bit mode, bytes 0-3 are unused, bytes 4-7 are the ALET, and bytes 8-15 are the address within the data space.

The __far keyword must appear in the declarator part of a pointer declaration, wherever a cv-qualifier can be used. For example,
int * __far p;
declares p to be a __far pointer to int.

__far pointers can appear in global scope and function scope, in simple assignment and in implicit assignment via function parameter passing. However, if they are used inside a function in operations that access the data space, such as dereferencing, the function must be in AR mode (that is, with the ARMODE compiler option in effect, or qualified with the armode function attribute).

A normal pointer can be converted to a __far pointer explicitly through typecasting or implicitly through assignment. The ALET of the __far pointer is set to zero. A __far pointer can be explicitly converted to a normal pointer through typecasting; the normal pointer keeps the offset of the __far pointer and the ALET is lost. A __far pointer cannot be implicitly converted to a normal pointer.

Pointer arithmetic is supported for __far pointers, with the ALET part being ignored. If the two ALETs are different, the results may have no meaning.

Two __far pointers can be compared for equality and inequality using the == and != operators. The whole pointer is compared. To compare for equality of the offset only, use the built-in function to extract the offset and then compare. To compare for equality of the ALET only, use the built-in function to extract the ALET and then compare. For more information on the set of built-in functions that operate on __far pointers, see z/OS® XL C/C++ Programming Guide.

Two __far pointers can be compared using the >, < , >=, and <= relational operators. The ALET parts of the pointers are ignored in this operation. There is no ordering between two __far pointers if their ALETs are different, and between a NULL pointer and any __far pointers. The result is meaningless if they are compared using relational operators.

When a __far pointer and a normal pointer are involved in an operation, the normal pointer is implicitly converted to __far before the operation. There is unspecified behavior if the ALETs are different. For example:
int * __far p;
int * __far q;
ptrdiff_t  chunk;
...

if (p == q) {
    p = p + 1024;
}

if (p < q) {
    chunk = q - p;
}
else {
    chunk = p - q;
}
The result of the & (address) operator is a normal pointer, except for the following cases:
  • If the operand of & is the result of an indirection operator (*), the type of & is the same as the operand of the indirection operator.
  • If the operand of & is the result of the arrow operator (->, structure member access), the type of & is the same as the left operand of the arrow operator.
For example:
int * __far p;
int * __far q;
...

q  =  &(*(p+2));  // result of & is a __far pointer; the ALET is the same as p.

struct  S {
   int b;
} * __far r;
...
q = & r->b;  // result of & is a __far pointer; the ALET is the same as r.
For more information on ARMODE and METAL compiler options, see ARMODE and METAL compiler options in the z/OS XL C/C++ User's Guide.