[an error occurred while processing this directive]

HP OpenVMS Systems

C Programming Language
Content starts here Compaq C

Compaq C
User's Guide for OpenVMS Systems


Previous Contents Index

If annotations are requested (and the /LISTING qualifier appears on the command line), the source listing section is shifted to the right and annotation numbers are added to the left of source lines. These numbers refer to brief descriptions that appear later in the source listing file.

Select one or more of the /ANNOTATIONS qualifier options shown in Table 1-2.

Table 1-2 /ANNOTATIONS Qualifier Options
Option Usage
ALL Selects all annotations. This output can be quite verbose because it includes detailed output for all annotations. For more concise output for each kind of annotation, use /ANNOTATIONS=(ALL,NODETAIL), or just /ANNOTATIONS with no qualifier options.
[NO]CODE Annotates the machine-code listing with descriptions of special instructions used for prefetching, alignment, and so on. The /MACHINE_CODE qualifier must also be specified for /ANNOTATION=CODE to have any visible effect.
[NO]DETAIL Provides additional level of annotation detail, where available.
[NO]FEEDBACK Indicates use of profile-directed feedback optimizations. Feedback optimizations are not implemented on OpenVMS systems, so this keyword has no visible effect.
[NO]INLINING Indicates where code for a called procedure was expanded inline.
[NO]LOOP_TRANSFORMS Indicates optimizations such as loop reordering and code hoisting.
[NO]LOOP_UNROLLING Indicates where advanced loop nest optimizations have been applied to improve cache performance (unroll and jam, loop fusion, loop interchange, and so on).
[NO]PREFETCHING Indicates where special instructions were used to reduce memory latency.
[NO]SHRINKWRAPPING Indicates removal of code establishing routine context when it is not needed.
[NO]SOFTWARE_PIPELINING Indicates where loops have been scheduled to hide functional unit latency.
[NO]TAIL_CALLS Indicates an optimization where a call from routine A to B can be replaced by a jump.
[NO]TAIL_RECURSION Indicates an optimization that eliminates unnecessary routine context for a recursive call.
NONE Same as /NOANNOTATIONS.

The default is /NOANNOTATIONS.

Specifying /ANNOTATIONS with no keywords is the same as specifying /ANNOTATIONS=(ALL,NODETAIL).

/[NO]ANSI_ALIAS (ALPHA ONLY)

Directs the compiler to assume the ANSI C aliasing rules. By so doing, the compiler has the freedom to generate better optimized code.

The aliasing rules referred to are explained in Section 3.3, paragraphs 20 and 25 of the ANSI C Standard, reprinted as follows:

An object shall have its stored value accessed only by an lvalue that has one of the following types:

  • the declared type of the object,
  • a qualified version of the declared type of the object,
  • a type that is the signed or unsigned type corresponding to the declared type of the object,
  • a type that is the signed or unsigned type corresponding to a qualified version of the declared type of the object,
  • an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union), or
  • a character type.

If your program does not access the same data through pointers of a different type (and for this purpose, signed and qualified versions of an otherwise same type are considered to be the same type), then assuming ANSI C aliasing rules allows the compiler to generate better optimized code.

If your program does access the same data through pointers of a different type (for example, by a "pointer to int " and a "pointer to float "), then you must not allow the compiler to assume ANSI C aliasing rules. Otherwise, incorrect code might be generated.

The default is /NOANSI_ALIAS for the /STANDARD=VAXC and /STANDARD=COMMON compiler modes. The default is /ANSI_ALIAS for all other modes.

/ARCHITECTURE (ALPHA ONLY)

Determines the type of Alpha chip code generated for a particular program. The /ARCHITECTURE qualifier uses the same keyword options (keywords) as the /OPTIMIZE=TUNE qualifier.

Where the /OPTIMIZE=TUNE qualifier is primarily used by certain higher-level optimizations for instruction scheduling purposes, the /ARCHITECTURE qualifier determines the type of code instructions generated for the program unit being compiled.

OpenVMS Version 7.1 and subsequent releases provide an operating system kernel that includes an instruction emulator. This emulator allows new instructions, not implemented on the host processor chip, to execute and produce correct results. Applications using emulated instructions will run correctly, but may incur significant software emulation overhead at runtime.

All Alpha processors implement a core set of instructions. Certain Alpha processor versions include additional instruction extensions.

Select one of the /ARCHITECTURE qualifier options shown in Table 1-3.

Table 1-3 /ARCHITECTURE Qualifier Options
Option Usage
GENERIC Generates code that is appropriate for all Alpha processor generations. This is the default.
HOST Generates code for the processor generation in use on the system being used for compilation.

Running programs compiled with this option on other implementations of the Alpha architecture may encounter instruction-emulation overhead.

EV4 Generates code for the 21064, 21064A, 21066, and 21068 implementations of the Alpha architecture.

Running programs compiled with the EV4 option will run without instruction-emulation overhead on all Alpha processors.

EV5 Generates code for some 21164 chip implementations of the Alpha architecture that use only the base set of Alpha instructions (no extensions).

Running programs compiled with the EV5 option will run without instruction-emulation overhead on all Alpha processors.

EV56 Generates code for some 21164 chip implementations that use the byte and word-manipulation instruction extensions of the Alpha architecture.

Running programs compiled with the EV56 option might incur emulation overhead on EV4 and EV5 processors, but will still run correctly on OpenVMS Version 7.1 (or higher) systems.

PCA56 Generates code for the 21164PC chip implementation that uses the byte- and word-manipulation instruction extensions and multimedia instruction extensions of the Alpha architecture.

Running programs compiled with the PCA56 option might incur emulation overhead on EV4, EV5, and EV56 processors, but will still run correctly on OpenVMS Version 7.1 (or higher) systems.

EV6 Generates code for the first-generation 21264 implementation of the Alpha architecture.
EV67 Generates code for the second-generation 21264 implementation of the Alpha architecture.

/ASSUME=(option,...)

Controls compiler assumptions. You can select one or more of the qualifier options described in Table 1-4.

Table 1-4 /ASSUME Qualifier Options
Option Usage
[NO]ACCURACY_SENSITIVE (ALPHA ONLY) Specifies whether certain code transformations that affect floating-point operations are allowed. These changes may or may not affect the accuracy of the program's results.
[NO]ALIGNED_OBJECTS (ALPHA ONLY) Controls an optimization for dereferencing pointers.
[NO]CLEAN_PARAMETERS (ALPHA ONLY) Controls compiler assumptions about short-integer formal parameters.
[NO]EXACT_CDD_OFFSETS Controls the alignment of Control Data Dictionary records.
[NO]HEADER_TYPE_DEFAULT Controls whether or not the default file-type mechanism for header files is enabled.
[NO]MATH_ERRNO (ALPHA ONLY) Controls whether or not intrinsic code is generated for math functions that set the errno variable.
[NO]POINTERS_TO_GLOBALS (ALPHA ONLY) Controls whether or not the compiler can safely assume that global variables have not had their addresses taken in code that is not visible to the current compilation.
[NO]WEAK_VOLATILE (ALPHA ONLY) Affects the generation of code for assignments to objects that are less than or equal to 16 bits in size that have been declared as volatile.
[NO]WHOLE_PROGRAM (ALPHA ONLY) Asserts to the compiler that except for "well-behaved library routines," the whole program consists only of the single object module being produced by this compilation.
[NO]WRITABLE_STRING_LITERALS Stores string constants in a writable psect. Otherwise, such constants are placed in a nonwritable psect.

The following sections describe these options in greater detail.

[NO]ACCURACY_SENSITIVE (ALPHA ONLY)

The default is ACCURACY_SENSITIVE.

If you specify NOACCURACY_SENSITIVE, the compiler is free to reorder floating-point operations based on algebraic identities (inverses, associativity, and distribution). This allows the compiler to move divide operations outside of loops, which improves performance.

The default, ACCURACY_SENSITIVE, directs the compiler to use only certain scalar rules for calculations. This setting can prevent some optimizations.

If you use the /ASSUME=NOACCURACY_SENSITIVE qualifier, Compaq C might reorder code (based on algebraic identities) to improve performance. The results can be different from the default (/ASSUME=ACCURACY_SENSITIVE) because of how the intermediate results are rounded. However, the NOACCURACY_SENSITIVE results are not categorically less accurate than those gained by the default.

[NO]ALIGNED_OBJECTS (ALPHA ONLY)

The default is /ASSUME=ALIGNED_OBJECTS.

On OpenVMS Alpha systems, dereferencing a pointer to a longword- or quadword-aligned object is more efficient than dereferencing a pointer to a byte- or word-aligned object. Therefore, the compiler can generate more optimized code if it makes the assumption that a pointer object of an aligned pointer type does point to an aligned object.

Since the compiler determines the alignment of the dereferenced object from the type of the pointer, and the program is allowed to compute a pointer that references an unaligned object (even though the pointer type indicates that it references an aligned object), the compiler must assume that the dereferenced object's alignment matches or exceeds the alignment indicated by the pointer type. Specifying /ASSUME=ALIGNED_OBJECTS (the default) allows the compiler to make such an assumption. With this assumption made, the compiler can generate more efficient code for pointer dereferences of aligned pointer types.

To prevent the compiler from assuming the pointer type's alignment for objects that it points to, use the /ASSUME=NOALIGNED_OBJECTS qualifier.

Before deciding whether to specify /ASSUME=NOALIGNED_OBJECTS or /ASSUME=ALIGNED_OBJECTS, you need to know what programming practices will affect your decision.

The compiler assumes that pointers point to objects that are aligned at least as much as the alignment of the pointer type. For example:

  • A pointer of type short points to objects that are at least short -aligned.
  • A pointer of type int points to objects that are at least int -aligned.
  • A pointer of type struct foo points to objects that have an alignment of struct foo (that is, the alignment of the strictest member alignment, or byte alignment if you have specified #pragma nomember_alignment for struct foo ).

If your module breaks this rule, your program will suffer alignment faults at runtime that can seriously degrade performance. If you can identify the places in your code where the rule is broken, use the __unaligned type qualifier. Otherwise, the /ASSUME=NOALIGNED_OBJECTS qualifier effectively treats all dereferences as if they were unaligned.

Compaq C for OpenVMS Alpha Systems aligns all nonmember declarations on natural boundaries, so by default all objects do comply with the previous assumption. Also, the standard library routine malloc on OpenVMS systems returns quadword-aligned heap memory.

A program can violate the previous assumption in any of the following ways:

  • By explicitly specifying a lesser alignment for an object than the pointer type's alignment
  • By casting a pointer to a pointer type of stricter alignment
  • By enclosing a member-aligned object inside a nonmember-aligned object

The following example explicitly specifies a lesser alignment for an object than the pointer type's alignment, which occurs when the address of an unaligned int member of a struct with #pragma nomember_alignment is used in a pointer dereference:


#pragma nomember_alignment
struct foo {
    char C;
    int i; /* i is unaligned because of char C */
};

struct foo st;
int        *i_p;

i_p = &st.i;

... *i_p ...    /* An expression containing a dereferenced i_p */

This example casts a pointer to a pointer type with stricter alignment:


int        *i_p;
char       *c_p;

.......
.......

i_p = (int *)c_p;

... *i_p ...    /* An expression containing a dereferenced i_p */

The following example encloses a member-aligned object inside a nonmember-aligned object:


#pragma member_alignment
struct inside {
    int i;  /* this type asserts that its objects have at least
               longword alignment (int is a longword)... */
};

#pragma nomember_alignment
struct outside {
    char C;
    struct inside s; /* ...but foo_ptr -> s is only byte-aligned! */
} *foo_ptr;

The expression foo_ptr -> s has a type whose alignment is explicitly specified to be longword (because longword is the strictest alignment of the structure's members), but the expression type is only guaranteed to be byte-aligned.

Also note that just as the pointer type information can direct the compiler to generate the appropriate code to dereference the pointer (code that does not cause alignment faults), it can also direct the compiler to generate even better code if it indicates that the object is at least longword-aligned.

[NO]CLEAN_PARAMETERS (ALPHA ONLY)

The default is /ASSUME=CLEAN_PARAMETERS.

The Alpha Calling Standard requires integers less than 64 bits long that are passed by value to have their upper bits either zeroed or sign-extended to make full 64-bit values. These are referred to as clean parameters. Some old code does not follow this convention. This can cause problems if the called program assumes that the caller followed the Calling Standard by passing only clean parameters.

Specifying /ASSUME=NOCLEAN_PARAMETERS allows a program to be called by old code that might pass unclean integer parameters. It directs the compiler to generate run-time code to clean the short integers so they comply with the Calling Standard.

[NO]EXACT_CDD_OFFSETS

The default is /ASSUME=NOEXACT_CDD_OFFSETS.

If /ASSUME=EXACT_CDD_OFFSETS is specified, the records input from the CDD are given the exact alignment (relative to the start of the record) specified by the CDD definition. This alignment is independent of the current compiler member-alignment setting.

If /ASSUME=NOEXACT_CDD_OFFSETS is specified, the compiler may modify the offsets specified in a CDD record according to the current member-alignment setting.

[NO]HEADER_TYPE_DEFAULT

The default is /ASSUME=HEADER_TYPE_DEFAULT.

In past versions of the C compiler, the #include directive always supplied a default file type of .h for C compilations. Similarly, the C++ compiler supplied a default file type of .hxx for C++ compilations.

However, the ANSI C++ standard requires that, for example, #include <iostream> be distinguishable from #include <iostream.hxx> . This is not possible with the header file-type default mechanism in effect.

You can disable the type default mechanism for either Compaq C or Compaq C++ by specifying /ASSUME=NOHEADER_TYPE_DEFAULT.

With /ASSUME=NOHEADER_TYPE_DEFAULT specified, an #include directive written with the standard syntax for header name (enclosed in quotes or angle brackets) will use the filename as specified, without supplying a default file type. More precisely stated, the default file type will be empty (just ".").

For example, a directory might contain three files named IOSTREAM., IOSTREAM.HXX, and IOSTREAM.H. By default, the C++ compiler processes #include <iostream> such that the file IOSTREAM.HXX is found, while the C compiler would find IOSTREAM.H.

However, if /ASSUME=NOHEADER_TYPE_DEFAULT is specified, the same directive causes the file IOSTREAM. to be found by both compilers, and the only way to include the file named IOSTREAM.HXX or IOSTREAM.H is to specify the .hxx or .h file type explicitly in the #include directive. Be aware that while the OpenVMS operating system treats filenames as case-insensitive and normally displays them in uppercase, filenames in #include directives should use lowercase for best portability. This is more in keeping with other C and C++ implementations.

[NO]MATH_ERRNO (ALPHA ONLY)

The default is /ASSUME=MATH_ERRNO, which does not allow intrinsic code for such math functions to be generated, even if /OPTIMIZE=INTRINSICS is in effect. Their prototypes and call formats, however, are still checked.

[NO]POINTERS_TO_GLOBALS (ALPHA ONLY)

The default is /ASSUME=POINTER_TO_GLOBALS, which directs the compiler to assume that global variables have had their addresses taken in separately compiled modules and that, in general, any pointer dereference could be accessing the same memory as any global variable. This is often a significant barrier to optimization.

The /ANSI_ALIAS command-line qualifier allows some resolution based on data type, but /ASSUME=NOPOINTER_TO_GLOBALS provides significant additional resolution and improved optimization in many cases.

/ASSUME=NOPOINTER_TO_GLOBALS tells the compiler that any global variable accessed through a pointer in the compilation must have had its address taken within that compilation. The compiler can see any code that takes the address of an extern variable. If it does not see the address of the variable being taken, the compiler can assume that no pointer points to the variable.

Consider the following code sequence:


extern int x;
...
int *p;
...
*p = 3;

Under /ASSUME=NOPOINTERS_TO_GLOBALS, the compiler can assume that x is not changed by the assignment through p when generating code. This can lead to faster code.

In combination with the /PLUS_LIST_OPTIMIZE qualifier, several source modules can be treated as a single compilation for the purpose of this analysis. Because run-time libraries such as the Compaq C RTL do not take the addresses of global variables defined in user programs, source modules can often be combined into a single compilation that allows /ASSUME=NOPOINTER_TO_GLOBALS to be used effectively.

Be aware that /ASSUME=NOPOINTERS_TO_GLOBALS does not tell the compiler that the compilation never uses pointers to access global variables (which is seldom true of real C programs).

[NO]WEAK_VOLATILE (ALPHA ONLY)

This option affects the generation of code for assignments to objects that are less than or equal to 16 bits in size (for example: char, short) that have been declared as volatile.

Specifying /ASSUME=WEAK_VOLATILE directs the compiler to generate code for volatile assignments to single bytes or words without using the load-locked store-conditional sequences that, in general, are required to assure volatile data integrity when direct byte or word memory-access instructions are not being used.

This option is intended for use in special I/O hardware access situations, and should not generally be used.

The default is /ASSUME=NOWEAK_VOLATILE, which uses interlocked instructions for sub-longword volatile accesses when byte or word instructions are not enabled.

[NO]WHOLE_PROGRAM (ALPHA ONLY)

The default is /ASSUME=NOWHOLE_PROGRAM.

The optimizations enabled by /ASSUME=WHOLE_PROGRAM include all those enabled by /ASSUME=NOPOINTER_TO_GLOBALS, and possibly additional optimizations as well.

[NO]WRITABLE_STRING_LITERALS

For /STANDARD=VAXC or /STANDARD=COMMON, the default is /ASSUME=WRITABLE_STRING_LITERALS.

For all other compiler modes, the default is /ASSUME=NOWRITABLE_STRING_LITERALS.

/[NO]CHECK[=([NO]UNINITIALIZED_VARIABLES, [NO]BOUNDS (ALPHA ONLY) [NO]POINTER_SIZE[=(option,...)])] (ALPHA ONLY)

This qualifier is for use as a debugging aid.

/CHECK=UNINITIALIZED_VARIABLES

Use /CHECK=UNINITIALIZED_VARIABLES to initialize all automatic variables to the value 0xfffa5a5afffa5a5a. This value is a floating NaN and, if used, causes a floating-point trap. If used as a pointer, this value is likely to cause an ACCVIO.

/CHECK=BOUNDS (ALPHA ONLY)

Use /CHECK=BOUNDS to enable run-time checking of array bounds. Array-bounds processing is performed in the following way:

  • Checks are done only when accessing an array.
  • Checks are not done when accessing a pointer, even if that access is done using the subscript operator. This means that checks are not done on arrays declared as formal parameters because they are considered pointers in the C language. If a formal parameter is a multi-dimension array, all bounds except the first are checked.
  • If an array is accessed using the subscript operator (as either the left or right operand), and the subscript operator is not the operand of an address-of operator, the check is for the index to be between 0 and the number of array elements minus one, inclusive.
  • If an array is accessed using the subscript operator (as either the left or right operand), and the subscript operator is the operand of the address-of operator, the check is for the index to be between 0 and the number of elements in the array, inclusive.
    The reason for treating the address-of case differently is that it is common programming practice to have a loop such as:


    int a[10];
    int *b;
    for (b = a ; b < &a[10] ; b++) { .... }
    

    In this case, access to &a[10] is allowed even though it is outside the range of the array.
  • If the array is being accessed using pointer addition, the check is for the value being added to be between 0 and the number of elements in the array, inclusive.
  • If the array is being accessed using pointer subtraction (that is, the subraction of an integer value from a pointer, not the subtraction of one pointer from another), the check is for the value being subtracted to be between the negation of the number of elements in the array and 0, inclusive.
  • In the previous three cases, an optional compile-time message (ident SUBSCRBOUNDS2) can be enabled to detect the case where an array has been accessed using either a constant subscript or constant pointer arithmetic, and the element accessed is exactly one past the end of the array.
  • Bounds checking is not done for arrays declared with one element. (Because ANSI C does not allow arrays without dimensions inside struct s, it is common practice to declare such arrays with a bounds specifier of 1.)
    In this case, an optional compile-time message (ident SUBSCRBOUNDS1) can be enabled to detect the case where an array declared with a single element is accessed using either a constant subscript or constant pointer arithmetic, and the element accessed is not part of the array.
  • Compaq C emits run-time checks for arrays indexed by constants, even though the compiler can and does detect this situation at compile-time. An exeption is that no run-time check is made if the compiler can determine that the access is valid.
  • Here are examples of some array references:


    int a[10];
    int *b;
    int c;
    
    int *d;
    int vla[c];
    int one[1];
    
    a[c] = 1;           // check c is from 0-9
    b[c] = 1;           // no check
    c[a] = 1;           // check c is from 0-9
    b = &a[c]           // check c is from 0-10
    *(a + c) = 1;       // check c is from 0-10
    *(a - c) = 1;       // check c is from -10 to 0
    d = a + c;          // check that c is from 0-10
    d = b + c;          // no check
    a[1] = 1;           // no run-time check - know access is valid
    vla[1] = 1;         // run-time check
    a[10] = 1;          // run-time check  (and compiler diagnostic)
    d = a + 10;         // no run-time check, optional SUBSCRBOUNDS2
                        //    message can be enabled
    c = one[5];         // no run-time check, optional SUBSCRBOUNDS1
                        //    message can be enabled
    
  • If a multi-dimension array is accessed, the compiler performs checks on each of the subscript expressions, making sure each is within the corresponding bound. So for the following code, the compiler checks that both x and y are between 0 and 9. It does not check that 10 * x + y is between 0 and 99:


    Previous Next Contents Index