VSI C language topics
1 – Block
A block is a compound statement. It allows more than one statement
to appear where a single statement ordinarily is used. It is made
up of a list of declarations and statements, enclosed in braces:
{ [declaration ...] [statement ...] }
The declaration list is optional; if it is included, all
declarations of variables are local to the block and supersede
previous declarations for the duration of the block. A block is
entered normally when control flows into it, or when a goto
statement transfers control to a label at the beginning of the
block. Each time the block is entered normally, storage is
allocated for auto or register variables. If, on the other hand, a
goto statement transfers control to a label inside the block or if
the block is the body of a switch statement, these storage
allocations do not occur. Blocks can be used wherever single
statements are valid -- for example, as the action clause of an if
statement:
if ( i < 1 )
{ /* BEGINNING OF BLOCK */
char x;
for (x = 'a'; x <= 'z'; x++)
printf("char = %c\n", x);
} /* END OF BLOCK */
2 – Valid File Specifications
In VSI C source programs, you can include both OpenVMS and UNIX*
style file specifications. Combinations of the two specifications
are not supported by VSI C.
Example of a valid UNIX* file specification:
beatle!/dba0/lennon/songs.lis.3
Example of an invalid UNIX* file specification:
BEATLE::DBA0:[LENNON.C]/songs.lis.3
----------
* UNIX is a trademark of The Open Group.
3 – Data Types
The data type of an object must be specified in its declaration.
The fundamental data types are the scalar types:
short int 16-bit signed integer
signed short int 16-bit signed integer
unsigned short int 16-bit unsigned integer
int 32-bit signed integer
signed int 32-bit signed integer
unsigned int 32-bit unsigned integer
long int 32-bit signed integer
signed long int 32-bit signed integer
unsigned long int 32-bit unsigned integer
long long int 64-bit signed integer
signed long long int 64-bit signed integer
unsigned long long int 64-bit unsigned integer
char 8-bit signed integer
signed char 8-bit signed integer
unsigned char 8-bit unsigned integer
wchar_t Long character (32-bit unsigned integer)
float 32-bit (single-precision) floating-point number
double 64-bit (double-precision) floating-point number
long double 128-bit (double-precision) floating-point
number
long float Interchangeable with double, but usage is
obsolete
_Bool An unsigned int that has the value 0 or 1
_Imaginary A C99-specified data type. In VSI C, use of
the _Imaginary keyword produces a warning,
which is resolved by treating it as an ordinary
identifier.
_Complex C99-specified data type available in all three
precisions: float _Complex, double _Complex,
or long double _Complex. A complex type has
the same representation and alignment
requirements as an array type containing
exactly two elements of the corresponding real
type; the first element is equal to the real
part, and the second element to the imaginary
part, of the complex number.
Note: This complex data type is similar to the
Fortran type, and has an associated header
file, <complex.h>. Although the fundamental
complex data types are implemented in the
compiler, the run-time support will not be
available until an OpenVMS Alpha release
following Version 7.3.
The signed keyword is the default. Declaring an object with int,
for example, is equivalent to declaring it with signed int.
However, char declarations should be explicitly declared, as the
compiler offers command-line options to change the default. If in
doubt, use signed char over char because signed char is more
portable.
Strings are arrays of characters terminated by the null character
(\0).
Also, view the contents of the <ints.h> header file for definitions
of platform-specific integer types.
3.1 – Array
An array is an aggregate of subscripted elements of the same type.
Elements of an array can have one of the fundamental data types or
can be structures, unions, or other arrays (multidimensional
arrays). An array is declared using square brackets. The
following example declares array1 to be an array of 10 integers.
The valid subscripts for array1 range from 0 to 9.
int array1[10];
The next example declares array2 to be a two-dimensional (2 by 3)
array of integers:
int array2[2][3];
The elements are stored in row-major order as follows:
array2[0][0], array2[0][1], ... array2[1][2].
3.2 – enum
An enumerated type is used to restrict the possible values of an
object to a predefined list. Elements of the list are called
enumeration constants.
The main use of enumerated types is to explicitly show the symbolic
names, and therefore the intended purpose, of objects that can be
represented with integer values. Objects of enumerated type are
interpreted as objects of type signed int, and are compatible with
objects of other integral types. The compiler automatically
assigns integer values to each of the enumeration constants,
beginning with 0.
An enumerated type is a set of scalar objects that have type names.
Variables are declared with enum specifiers in the place of the
type specifier. An enumerated type can have one of the following
forms:
enum { enumerator,... }
enum tag { enumerator,... }
enum tag
Each enumerator defines a constant of the enumerated type (tag).
The enumerator list forms an ordered list of the type's values.
Each enumerator has the form "identifier [= expression]", where the
"identifier" is the name to be used for the constant value and the
optional "expression" gives its integer equivalent. If a tag
appears but no list of enumerators, the enum-specifier refers to a
previous definition of the enumerated type, identified by the tag.
The following example declares an enumerated object
'background_color' with a list of enumeration constants:
enum colors { black, red, blue, green, } background_color;
Later in the program, a value can be assigned to the object
'background_color':
background_color = red;
In this example, the compiler automatically assigns the integer
values as follows: black = 0, red = 1, blue = 2, and green = 3.
Alternatively, explicit values can be assigned during the
enumerated type definition:
enum colors { black = 5, red = 10, blue, green = black+2 };
Here, black equals the integer value 5, red = 10, blue = 11, and
green = 7. Note that blue equals the value of the previous
constant (red) plus one, and green is allowed to be out of
sequential order.
Because the ANSI C standard is not strict about assignment to
enumerated types, any assigned value not in the predefined list is
accepted without complaint.
3.3 – Pointer
A pointer in C is a variable that holds the address of another
variable. Pointers are declared with the asterisk operator. For
example:
int i, *ip, *np; /* i IS AN INTEGER, ip AND np ARE
POINTERS TO INTEGERS */
The following operations are permitted on pointers:
o Assigning an address to the pointer (as in ip = &i;)
o Fetching the object of the pointer (by dereferencing the
pointer) with the asterisk operator (i = *ip;, which
assigns the addressed integer to i)
o Adding (as in ip += 5;, which makes ip point to the object
that is five longwords away from the initial address in ip)
o Subtracting (as in i = np - ip;, which gives the number of
objects separating the objects pointed to by np and ip)
3.4 – Structure
A structure is an aggregate of members whose data types can differ.
Members can be scalar variables, arrays, structures, unions, and
pointers to any object. The size of a structure is the sum of the
sizes of its members, which are stored in the order of their
declarations. Structures are defined with the keyword struct,
followed by an optional tag, followed by a structure-declaration
list in braces. The syntax is:
struct [identifier] { struct-declaration ... }
Each struct-declaration is a type specifier (type keyword, struct
tag, union tag, enum tag, or typedef name) followed by a list of
member declarators:
type-specifier member-declarator,... ;
Each member declarator defines either an ordinary variable or a bit
field:
declarator
or
[declarator] : constant-expression
The following example declares a new structure employee with two
structure variables bob and susan of the structure type employee:
struct employee {
char *name;
int birthdate; /* name, birthdate, job_code, and salary are */
int job_code; /* treated as though declared with const. */
float salary;
};
struct employee bob, susan;
3.5 – typedef
Use the typedef keyword to define an abbreviated name, or
synonym, for a lengthy type definition. Grammatically,
typedef is a storage-class specifier, so it can precede any valid
declaration. In such a declaration, the identifiers name types
instead of variables. For example:
typedef char CH, *CP, STRING[10], CF();
In the scope of this declaration, CH is a synonym for "character,"
CP for "pointer to character," STRING for "10-element array of
characters," and CF for "function returning a character." Each of
the type definitions can be used in that scope to declare
variables. For example:
CF c; /* c IS A FUNCTION RETURNING A CHARACTER */
STRING s; /* s IS A 10-CHARACTER STRING */
3.6 – Union
A union is an aggregate of members whose data types can differ.
Members can be scalar variables, arrays, structures, unions, and
pointers to any object. The size of a union is the size of its
longest member plus any padding needed to meet alignment
requirements. All its members occupy the same storage. Unions are
defined with the union keyword, followed by an optional tag,
followed by a union-declaration list in braces. The syntax is:
union [identifier] { union-declaration ... }
Each union-declaration is a type specifier (type keyword, struct
tag, union tag, enum tag, or typedef name) followed by a list of
member declarators:
type-specifier member-declarator,... ;
Each member declarator defines either an ordinary variable or a bit
field:
declarator
or
[declarator] : constant-expression
Once a union is defined, a value can be assigned to any of the
objects declared in the union declaration. For example:
union name {
dvalue;
struct x { int value1; int value2; };
float fvalue;
} alberta;
alberta.dvalue = 3.141596; /*Assigns pi to the union object*/
Here, alberta can hold a double, struct, or float value. The
programmer has responsibility for tracking the current type
contained in the union. The type is maintained until explicitly
changed. An assignment expression can be used to change the type of
value held in the union.
3.7 – Void
You can use the void data type to declare functions that do not return a value. Functions declared to be of this type cannot contain return statements and cannot be used in statements where a return value is expected. The void data type can be used in the cast operation if casting to a "function without a return value ...". You can also use the void data type with pointers.
4 – Declarations
Declarations specify the functions and variables referenced in a
program. Declarations in C have the following syntax:
declaration:
declaration-specifiers [init-declarator-list];
declaration-specifiers:
storage-class-specifier [declaration-specifiers]
type-specifier [declaration-specifiers]
type-qualifier [declaration-specifiers]
init-declarator-list:
init-declarator
init-declarator-list, init-declarator
init-declarator:
declarator
declarator = initializer
Note the following items about the general syntax of a declaration:
o The storage-class-specifier, type-qualifier, and type-specifier
can be listed in any order. All are optional, but, except for
function declarations, at least one such specifier or qualifier
must be present. Placing the storage-class-specifier anywhere
but at the beginning of the declaration is an obsolete style.
o Storage-class keywords are auto, static, extern, and register.
o Type qualifiers are const, volatile, __restrict, and
__unaligned.
o The declarator is the name of the object being declared. A
declarator can be as simple as a single identifier, or can be a
complex construction declaring an array, structure, pointer,
union, or function (such as *x, tree(), and treebar[10]).
o Initializers are optional and provide the initial value of an
object. An initializer can be a single value or a
brace-enclosed list of values, depending on the type of object
being declared.
o A declaration determines the beginning of an identifier's
scope.
o An identifier's linkage is determined by the declaration's
placement and its specified storage class.
Consider the following example:
volatile static int var_number = 10;
This declaration shows a qualified type (a type, int, with a type
qualifier, volatile), a storage class (static), a declarator (data),
and an initializer (10). This declaration is also a definition,
because storage is reserved for the data object var_number.
For more information, see HELP CC LANGUAGE_TOPICS DATA_TYPES, HELP
CC LANGUAGE_TOPICS STORAGE_CLASSES, and HELP CC LANGUAGE_TOPICS
TYPE_QUALIFIERS.
4.1 – Interpretation
The symbols used in declarations are C operators, subject to the
usual rules of precedence and associativity. These operators are
parentheses, brackets, and asterisks for "function returning...",
"array of...", and "pointer to...", respectively. Parentheses and
brackets associate left to right; asterisk operators associate
right to left. Parentheses and brackets have the same precedence,
which is higher than that of asterisks. Parentheses are also used
to change the associativity of the other operators.
The following declaration, for example, is a "function returning a
pointer to an array of pointers to char":
char * ( *x() ) [];
This is how the declaration is broken down to determine what it is:
char * ( *x() ) [];
* ( *x() ) [] is char
( *x() ) [] is (pointer to) char
*x() is (array of) (pointer to) char
x() is (pointer to) (array of) (pointer to)
char
x is (function returning) (pointer to)
(array of) (pointer to) char
In this sort of breakdown, lower precedence operators are removed
first. With two equal precedence operators, remove the rightmost
if they are left-to-right operators, and the leftmost if they are
right-to-left operators. For example, "[]()" means "array of
functions returning...".
5 – Functions
Functions consist of one or more blocks of statements that perform
one logical operation. They can be called from other functions
either in the same program or in different programs. A function
may exchange values with the calling function by use of parameters.
Function declarations have the following syntax:
function_name()
or
function_name(arg1, arg2,...)
or
function_name(data-type arg1, data-type arg2,...)
In the first form of the function declaration, the function takes
no arguments. In the second form, the function takes arguments;
the arguments are declared outside the parameter list. In the
third form, the function declaration is a function prototype that
specifies the type of its arguments in the identifier list; the
prototype form is recommended. In all three cases, the parenthesis
after the function name are required.
VSI C for OpenVMS Systems provides a library of common functions.
These functions perform standard I/O operations, character and
string handling, mathematical operations, miscellaneous system
services, and UNIX* system emulation. For more information, see
HELP CRTL.
----------
* UNIX is a trademark of The Open Group.
6 – Builtin Functions
Built-in functions allow you to directly access hardware and machine instructions to perform operations that are cumbersome, slow, or impossible in pure C. These functions are very efficient because they are built into the VSI C compiler. This means that a call to one of these functions does not result in a reference to a function in the C run-time library or in your programs. Instead, the compiler generates the machine instructions necessary to carry out the function directly at the call site. Because most of these built-in functions closely correspond to single VAX, Alpha, or Itanium machine instructions, the result is small, fast code. Some of these functions (such as those that operate on strings or bits) are of general interest. Others (such as the functions dealing with process context) are of interest if you are writing device drivers or other privileged software. Some of the functions are privileged and unavailable to user mode programs. Be sure to include the <builtins.h> header file in your source program to access these built-in functions. VSI C supports the #pragma builtins preprocessor directive for compatibility with VAX C, but it is not required. Some of the built-in functions have optional arguments or allow a particular argument to have one of many different types. To describe different valid combinations of arguments, the description of each built-in function may list several different prototypes for the function. As long as a call to a built-in function matches one of the prototypes listed, the call is valid. Furthermore, any valid call to a built-in function acts as if the corresponding prototype was in scope, so the compiler performs the argument checking and argument conversions specified by that prototype. The majority of the built-in functions are named after the machine instruction that they generate. For more information on these built-in functions, see the documentation on the corresponding machine instruction. In particular, see that reference for the structure of queue entries manipulated by the queue built-in functions.
6.1 – Alpha Compatibility
The VSI C built-in functions available on OpenVMS Alpha systems are
also available on I64 systems, with some differences:
o There is no support for the asm, fasm, and dasm intrinsics
(declared in the <c_asm.h> header file).
o The functionality provided by the special-case treatment of R26
on an Alpha system asm, as in asm("MOV R26,R0"), is provided by
a new built-in function for I64 systems:
__int64 __RETURN_ADDRESS(void);
o The only PAL function calls implemented as built-in functions
within the compiler are the 24 queue-manipulation builtins.
The queue manipulation builtins generate calls to new OpenVMS
system services SYS$<name>, where <name> is the name of the
builtin with the leading underscores removed.
Any other OpenVMS PAL calls are supported through macros
defined in the <pal_builtins.h> header file included in the
<builtins.h> header file. Typically, the macros in
<pal_builtins.h> transform an invocation of an Alpha system
builtin into a call to a system service that performs the
equivalent function on an I64 system. Two notable exceptions
are __PAL_GENTRAP and __PAL_BUGCHK, which instead invoke the
I64 specific compiler builtin __break2.
o There is no support for the various floating-point built-in
functions used by the OPenVMS math library (for example,
operations with chopped rounding and conversions).
o For most built-in functions that take a retry count, the
compiler issues a warning message, evaluates the count for
possible side effects, ignores it, and then invokes the same
function without a retry count. This is necessary because the
retry behavior allowed by Alpha load-locked/store-conditional
sequences does not exist on I64 systems. There are two
exceptions to this: __LOCK_LONG_RETRY and
__ACQUIRE_SEM_LONG_RETRY; in these cases, the retry behavior
involves comparisons of data values, not just
load-locked/store-conditional.
o The __CMP_STORE_LONG and __CMP_STORE_QUAD built-in functions
produce either a warning or an error, depending on whether or
not the compiler can determine if the source and destination
addresses are identical. If the addresses are identical, the
compiler treats the builtin as the new __CMP_SWAP_ form and
issues a warning. Otherwise it is an error.
6.2 – <builtins.h>
The <builtins.h> header file contains a section at the top
conditionalized to just __ia64 with the support for built-in
functions specific to I64 systems. This includes macro definitions
for all of the registers that can be specified to the __getReg,
__setReg, __getIndReg, and __setIndReg built-in functions.
Parameters that are const-qualified require an argument that is a
compile-time constant.
Notes:
o The <builtins.h> header file contains comments noting which
built-in functions are not available or are not the
preferred form for I64 systems. The compiler issues
diagnostics where using a different built-in function for
I64 systems would be preferable.
o The comments in <builtins.h> reflect only what is explicitly
present in that header file itself, and in the compiler
implementation. You should also consult the content and
comments in <pal_builtins.h> to determine more accurately
what functionality is effectively provided by including
<builtins.h>. For example, if a program explicitly declares
one of the Alpha built-in functions and invokes it without
having included <builtins.h>, the compiler might issue a
BIFNOTAVAIL error message, regardless of whether or not the
function is available through a system service. If the
compilation does include <builtins.h>, and BIFNOTAVAIL is
issued, then either there is no support at all for the
built-in function or a new version of <pal_builtins.h> is
needed.
6.3 – __break
Generates a break instruction with an immediate.
Syntax:
void __break (const int __break_arg);
6.4 – __break2
Implements the Alpha __PAL_GENTRAP and __PAL_BUGCHK built-in
functions on OpenVMS I64 systems.
The __break2 function is equivalent to the __break function with
the second parameter passed in general register 17:
R17 = __R17_value; __break (__break_code);
Syntax:
void __break2 (__Integer_Constant __break_code, unsigned
__int64 __r17_value);
6.5 – CMP SWAP LONG
Performs a conditional atomic compare and exchange operation on a
longword. The longword pointed to by source is read and compared
with the longword old_value. If they are equal, the longword
new_value is written into the longword pointed to by source. The
read and write is performed atomically, with no intervening access
to the same memory region.
The function returns 1 if the write occurs, and 0 otherwise.
Syntax:
int __CMP_SWAP_LONG (volatile void *source, int old_value, int
new_value);
6.6 – CMP SWAP QUAD
Performs a conditional atomic compare and exchange operation on a
quadword. The quadword pointed to by source is read and compared
with the quadword old_value. If they are equal, the quadword
new_value is written into the quadword pointed to by source. The
read and write is performed atomically, with no intervening access
to the same memory region.
The function returns 1 if the write occurs, and 0 otherwise.
Syntax:
int __CMP_SWAP_QUAD (volatile void *source, int old_value, int
new_value);
6.7 – CMP SWAP LONG ACQ
Performs a conditional atomic compare and exchange operation with
acquire semantics on a longword. The longword pointed to by source
is read and compared with the longword old_value. If they are
equal, the longword new_value is written into the longword pointed
to by source. The read and write is performed atomically, with no
intervening access to the same memory region.
Acquire memory ordering guarantees that the memory read/write is
made visible before all subsequent data accesses to the same memory
location by other processors.
The function returns 1 if the write occurs, and 0 otherwise.
Syntax:
int __CMP_SWAP_LONG_ACQ (volatile void *source, int old_value,
int new_value);
6.8 – CMP SWAP QUAD ACQ
Performs a conditional atomic compare and exchange operation with
acquire semantics on a quadword. The quadword pointed to by source
is read and compared with the quadword old_value. If they are
equal, the quadword new_value is written into the quadword pointed
to by source. The read and write is performed atomically, with no
intervening access to the same memory region.
Acquire memory ordering guarantees that the memory read/write is
made visible before all subsequent memory data accesses to the same
memory location by other processors.
The function returns 1 if the write occurs, and 0 otherwise.
Syntax:
int __CMP_SWAP_QUAD_ACQ (volatile void *source, int old_value,
int new_value);
6.9 – CMP SWAP LONG REL
Performs a conditional atomic compare and exchange operation with
release semantics on a longword. The longword pointed to by source
is read and compared with the longword old_value. If they are
equal, the longword new_value is written into the longword pointed
to by source. The read and write is performed atomically, with no
intervening access to the same memory region.
Release memory ordering guarantees that the memory read/write is
made visible after all previous data memory acceses to the same
memory location by other processors.
The function returns 1 if the write occurs, and 0 otherwise.
Syntax:
int __CMP_SWAP_LONG_REL (volatile void *source, int old_value,
int new_value);
6.10 – CMP SWAP QUAD REL
Performs a conditional atomic compare and exchange operation with
release semantics on a quadword. The quadword pointed to by source
is read and compared with the quadword old_value. If they are
equal, the quadword new_value is written into the quadword pointed
to by source. The read and write is performed atomically, with no
intervening access to the same memory region.
Release memory ordering guarantees that the memory read/write is
made visible after all previous data memory acceses to the same
memory location by other processors.
The function returns 1 if the write occurs, and 0 otherwise.
Syntax:
int __CMP_SWAP_QUAD_REL (volatile void *source, int old_value,
int new_value);
6.11 – RETURN ADDRESS
Produces the address to which the function containing the built-in
call will return as a 64-bit integer (on Alpha systems, the value
of R26 on entry to the function; on I64 systems, the value of B0 on
entry to the function).
This built-in function cannot be used within a function specified
to use nonstandard linkage.
Syntax:
__int64 __RETURN_ADDRESS (void);
6.12 – __dsrlz
Serializes data. Maps to the srlz.d instruction.
Syntax:
void __dsrlz (void);
6.13 – __fc
Flushes a cache line associated with the address given by the
argument. Maps to the fcr instruction.
Syntax:
void __fc (__int64 __address);
6.14 – __flushrs
Flushes the register stack.
Syntax:
void __flushrs (void);
6.15 – __fwb
Flushes the write buffers. Maps to the fwb instruction.
Syntax:
void __fwb (void);
6.16 – getIndReg
Returns the value of an indexed register. The function accesses a
register (index) in a register file (whichIndReg) of 64-bit
registers.
Syntax:
unsigned __int64 __getIndReg (const int whichIndReg, __int64
index);
6.17 – getReg
Gets the value from a hardware register based on the register index
specified. This function produces a corresponding mov = r
instruction.
Syntax:
unsigned __int64 __getReg (const int whichReg);
6.18 – InterlockedCompareExchange acq
Atomically compares and exchanges the value specified by the first
argument (a 64-bit pointer). This function maps to the
cmpxchg4.acq instruction with appropriate setup.
The value at *Destination is compared with the value specified by
Comparand. If they are equal, Newval is written to *Destination,
and Oldval is returned. The exchange will have taken place if the
value returned is equal to the Comparand. The following algorithm
is used:
ar.ccv = Comparand;
Oldval = *Destination; //Atomic
if (ar.ccv == *Destination) //Atomic
*Destination = Newval; //Atomic
return Oldval;
Those parts of the algorithm marked "Atomic" are performed
atomically by the cmpxchg4.acq instruction. This instruction has
acquire ordering semantics; that is, the memory read/write is made
visible prior to all subsequent data memory accesses of the
Destination by other processors.
Syntax:
unsigned __int64 _InterlockedCompareExchange_acq (volatile
unsigned int *Destination, unsigned __int64 Newval, unsigned
__int64 Comparand);
6.19 – InterlockedCompareExchange64 acq
Same as the _InterlockedCompareExchange_acq function, except that
those parts of the algorithm that are marked "Atomic" are performed
by the cmpxchg8.acq instruction.
Syntax:
unsigned __int64 _InterlockedCompareExchange64_acq (volatile
unsigned int64 *Destination, unsigned __int64 Newval, unsigned
__int64 Comparand);
6.20 – InterlockedCompareExchange rel
Same as the _InterlockedCompareExchange_acq function except that
those parts of the algorithm that are marked "Atomic" are performed
by the cmpxchg4.rel instruction with release ordering semantics;
that is, the memory read/write is made visible after all previous
memory accesses of the Destination by other processors.
Syntax:
unsigned __int64 _InterlockedCompareExchange_rel (volatile
unsigned int *Destination, unsigned __int64 Newval, unsigned
__int64 Comparand);
6.21 – InterlockedCompareExchange64 rel
Same as the _InterlockedCompareExchange_rel function, except that
those parts of the algorithm that are marked "Atomic" are performed
by the cmpxchg8.rel instruction.
Syntax:
unsigned __int64 _InterlockedCompareExchange64_rel (volatile
unsigned int64 *Destination, unsigned __int64 Newval, unsigned
__int64 Comparand);
6.22 – __invalat
Invalidates ALAT. Maps to the invala instruction.
Syntax:
void __invalat (void);
6.23 – __invala
Same as the __invalat function.
Syntax:
void __invala (void);
6.24 – __isrlz
Executes the serialize instruction. Maps to the srlz.i
instruction.
Syntax:
void __isrlz (void);
6.25 – __itcd
Inserts an entry into the data translation cache. Maps to the
itc.d instruction
Syntax:
void __itcd (__int64 pa);
6.26 – __itci
Inserts an entry into the instruction translation cache. Maps to
the itc.i instruction.
Syntax:
void __itci (__int64 pa);
6.27 – __itrd
Maps to the itr.d instruction.
Syntax:
void __itrd (__int64 whichTransReg, __int64 pa);
6.28 – __itri
Maps to the itr.i instruction.
Syntax:
void __itri (__int64 whichTransReg, __int64 pa);
6.29 – __loadrs
Loads the register stack.
Syntax:
void __loadrs (void);
6.30 – __prober
Determines whether read access to the virtual address specified by
__address bits {60:0} and the region register indexed by __address
bits {63:61} is permitted at the privilege level given by __mode
bits {1:0}. It returns 1 if the access is permitted, and 0
otherwise.
This function can probe only with equal or lower privilege levels.
If the specified privilege level is higher (lower number), then the
probe is performed with the current privilege level.
This function is the same as the Intel __probe_r function.
Syntax:
int __prober (__int64 __address, unsigned int __mode);
6.31 – __probew
Determines whether write access to the virtual address specified by
__address bits {60:0} and the region register indexed by __address
bits {63:61}, is permitted at the privilege level given by __mode
bits {1:0}. It returns 1 if the access is permitted, and 0
otherwise.
This function can probe only with equal or lower privilege levels.
If the specified privilege level is higher (lower number), then the
probe is performed with the current privilege level.
This function is the same as the Intel __probe_w function.
Syntax:
int __probew (__int64 __address, unsigned int __mode);
6.32 – __ptce
Maps to the ptc.e instruction.
Syntax:
void __ptce (__int64 va);
6.33 – __ptcl
Purges the local translation cache. Maps to the ptc.l r,r
instruction.
Syntax:
void __ptcl (__int64 va, __int64 pagesz);
6.34 – __ptcg
Purges the global translation cache. Maps to the ptc.g r,r
instruction.
Syntax:
void __ptcg (__int64 va, __int64 pagesz);
6.35 – __ptcga
Purges the global translation cache and ALAT. Maps to the ptc.ga
r,r instruction.
Syntax:
void __ptcga (__int64 va, __int64 pagesz);
6.36 – __ptri
Purges the instruction translation register. Maps to the ptr.i r,r
instruction.
Syntax:
void __ptri (__int64 va, __int64 pagesz);
6.37 – __ptrd
Purges the data translation register. Maps to the ptr.d r,r
instruction.
Syntax:
void __ptrd (__int64 va, __int64 pagesz);
6.38 – __rum
Resets the user mask.
Syntax:
void __rum (int mask);
6.39 – __rsm
Resets the system mask bits of the PSR. Maps to the rsm imm24
instruction.
Syntax:
void __rsm (int mask);
6.40 – setIndReg
Copies a value into an indexed register. The function accesses a
register (index) in a register file (whichIndReg) of 64-bit
registers.
Syntax:
void __setIndReg (const int whichIndReg, __int64 index,
unsigned __int64 value);
6.41 – setReg
Sets the value for a hardware register based on the register index
specified. This function produces a corresponding mov = r
instruction.
Syntax:
void __int64 __setReg (const int whichReg, unsigned __int64
value);
6.42 – __ssm
Sets the system mask.
Syntax:
void __ssm (int mask);
6.43 – __sum
Sets the user mask bits of the PSR. Maps to the sum imm24
instruction.
Syntax:
void __sum (int mask);
6.44 – __synci
Enables memory synchronization. Maps to the sync.i instruction.
Syntax:
void __synci (void);
6.45 – __tak
Returns the translation access key.
Syntax:
unsigned int __tak (__int64 __address);
6.46 – __tpa
Translates a virtual address to a physical address.
Syntax:
__int64 __tpa(__int64 __address);
6.47 – __thash
Generates a translation hash entry address. Maps to the thash r =
r instruction.
Syntax:
void __thash(__int64 __address);
6.48 – __ttag
Generates a translation hash entry tag. Maps to the ttag r=r
instruction.
Syntax:
void __ttag(__int64 __address);
7 – Variable Length Argument Lists
The set of functions and macros defined and declared in the
<varargs.h> and the <stdarg.h> header files provide a method of
accessing variable-length argument lists. (Note that the
<stdarg.h> functions are defined by the ANSI C standard and are,
therefore, portable as compared with those defined in <varargs.h>.)
The VSI C RTL functions such as printf and execl, for example, use
variable-length argument lists. User-defined functions with
variable-length argument lists that do not use <varargs.h> or
<stdarg.h> are not portable due to the different argument-passing
conventions of various machines.
To use these functions and macros in <stdarg.h>, you must include
the <stdarg.h> header file with the following preprocessor
directive:
#include <stdarg.h>
The <stdarg.h> header file declares a type (va_list) and three
macros (va_start, va_arg, and va_end) for advancing through a list
of function arguments of varying number and type. The macros have
the following syntax:
void va_start(va_list ap, parmN);
type va_arg(va_list ap, type);
void va_end(va_list ap);
The va_start macro initializes the object ap of type va_list for
subsequent use by va_arg and va_end. The va_start macro must be
invoked before any access to the unnamed arguments. The parameter
parmN is the identifier of the rightmost parameter in the variable
parameter list of the function definition. If parmN is declared
with the register storage class, with a function or array type, or
with a type that is not compatible with the type that results after
application of the default arguments promotions, the behavior is
undefined. The va_start macro returns no value.
The va_arg macro expands to an expresion that has the type and
value of the next argument in the call. The parameter ap is the
same as the one initialized by va_start. Each invocation of va_arg
modifies ap so that the values of successive arguments are returned
in turn. The parameter "type" is a type name specified such that
the type of a pointer to an object that has the specified type can
be obtained by postfixing an asterisk (*) to "type". If there is
no actual next argument, or if type is not compatible with the type
of the next actual argument (as promoted according to the default
argument promotions), the behavior is undefined. The first
invocation of va_arg after that of va_start returns the value of
the argument after that specified by parmN. Successive invocations
return the values of the remaining arguments in turn.
The va_end macro facilitates a normal return from the function
whose variable argument list was referred to by the expansion of
va_start that initialized the va_list ap object. The va_end macro
can modify ap) so that it can no longer be used (without an
intervening invocation of va_start). If there is no corresponding
invocation of va_start or if va_end is not invoked before the
return, the behavior is undefined. The va_end macro returns no
value.
8 – Preprocessor
The VSI C preprocessor uses directives to affect the compilation of a source file. For VSI C on OpenVMS systems, these directives are processed by an early phase of the compiler, not by a separate program. The preprocessor directives begin with a number sign (#) and do not end with a semicolon. The number sign must appear in the first column of the source line.
8.1 – Null directive (#)
A preprocessing directive of the form # <newline> is a null directive and has no effect.
8.2 – Conditional Compilation
Conditional compilation is provided by the following directives:
#if constant-expression
Checks whether the constant expression is nonzero (true).
#ifdef identifier
Checks whether the identifier is defined.
#ifndef identifier
Checks whether the identifier is undefined.
#else
Introduces source lines to be compiled as an alternative to the
conditions tested by the previous directives.
#elif constant-expression
Delimits alternative source lines to be compiled if the constant
expression in the corresponding #if, #ifdef, or #ifndef
directive is false and if the additional constant expression
presented in the #elif directive is true. An #elif directive is
optional.
#endif
Ends the scope of the previous directives.
If the condition checked by #if, #ifdef, or #ifndef is true, then
all lines between the #else, #elif, and #endif are ignored. If the
condition is false, then any lines between the conditional
directive and the #else or #elif (if any) are ignored. If there is
no #else, then the lines between the conditional and the #endif are
ignored.
8.3 – #define
The #define preprocessor directive has the form:
#define identifier token-string
The preprocessor substitutes the token string everywhere in the
program that it finds the identifier except within comments,
character constants, or string constants.
Macro replacements are defined in a #define directive of the
following form:
#define name([parm1[,parm2,...]]) token-string
Within the program, all macro references that have the following
form are replaced by the token string. The arguments in the macro
reference replace the corresponding parameters in the token string.
name([arg1[,arg2,...]])
8.4 – #dictionary
The #dictionary directive is retained for compatibility with VAX C
and is supported only when running the VSI C compiler in VAX C mode
(/STANDARD=VAXC). See also the ANSI C equivalent #pragma
dictionary directive.
The #dictionary directive extracts Common Data Dictionary (CDD)
definitions from the specified dictionary. These definitions are
then translated into VSI C and included in the program.
The #dictionary directive has the following form:
#dictionary "cdd_path"
The cdd_path is a character string that gives the path name of the
CDD record. It can also be a macro that resolves to such a
character string.
8.5 – #error
The #error directive issues an optional diagnostic message, and
ends compilation. This directive has the following form:
#error [message] <newline>
8.6 – #include
The #include directive instructs the preprocessor to insert the
contents of the specified file or module into the program. An
#include directive can have one of three forms:
#include "filespec"
#include <filespec>
#include module-name
The first two forms are ANSI-compliant methods of file inclusion
and are therefore more portable. In these forms, .h is the default
file type, unless the compiler is instructed to supply no default
type (that is, a type of just ".") by the
/ASSUME=NOHEADER_TYPE_DEFAULT qualifier.
The third form is specific to OpenVMS systems for specifying the
inclusion of a module from a text library, and is not generally
needed or recommended because the ANSI forms also cause the text
libraries to be searched.
For the order of search, see /INCLUDE_DIRECTORY.
There is no defined limit to the nesting level of #include files
and modules.
8.7 – #line
The #line directive applies a specified line number and optional
file specification to the next line of source text. This can be
useful for diagnostic messages. The #line directive has the
following forms:
#line integer-constant <newline>
#line integer-constant "filename" <newline>
#line pp-tokens <newline>
In the first two forms, the compiler gives the line following a
#line directive the number specified by the integer constant. The
optional filename in quotation marks indicates the name of the
source file that the compiler will provide in its diagnostic
messages. If the filename is omitted, the file name used is the
name of the current source file or the last filename specified in a
previous #line directive.
In the third form, macros in the #line directive are expanded
before it is interpreted. This allows a macro call to expand into
the integer-constant, filename, or both. The resulting #line
directive must match one of the other two forms, and is then
processed as appropriate.
8.8 – #module
The #module directive is retained for compatibility with VAX C and
is supported only when running the VSI C compiler in VAX C mode
(/STANDARD=VAXC). See also the ANSI C equivalent #pragma module
directive.
The #module directive passes information about an object module to
the compiler.
The #module directive can have one of the following forms:
#module identifier identifier
#module identifier string
The first argument of the directive is an VSI C identifier or macro
that resolves to an identifier. It gives the system-recognized
(for example, internally recognized by the debugger and the
librarian) name of the module; the object file name remains the
same. The second argument specifies the optional identification
that appears on listings. This may be either a VAX C identifier, a
character-string constant with no more than 31 characters, or a
macro that resolves to one of these.
There can be only one #module directive per compilation. It can
appear anywhere before the C language text.
8.9 – #pragma
The #pragma preprocessor directive performs compiler-specific tasks
as designated by each implementation of the C language.
All pragmas have a <pragma-name>_m version, which makes the pragma
subject to macro replacement. For example, #pragma assert is not
subject to macro expansion, but #pragma assert_m is.
All pragmas also have a <pragma-name>_nm version, which prevents
macro expansion. For example, #pragma inline is subject to macro
expansion, but #pragma inline_nm is not.
There is also a _Pragma operator (C99 Standard), which destringizes
its string literal argument, effectively allowing #pragma
directives to be produced by macro expansion. When specified using
this operator, the tokens of the pragma, which appear together
within a single string literal in this form, are not macro
expanded, even if they have an "_m" suffix. But macro expansion
can be accomplished if desired by using the stringization operator
(#) to form the string.
The _Pragma operator has the following syntax:
_Pragma ( string-literal )
VSI C for OpenVMS Systems supports the following #pragma
directives:
#pragma assert[_m|_nm]
Lets you specify assertions that the compiler can make about a
program to generate more efficient code.
The #pragma assert directive is never needed to make a program
execute correctly, however if a #pragma assert is specified,
the assertions must be valid or the program might behave
incorrectly.
Syntax:
#pragma assert func_attrs(identifier-list)function-assertions
#pragma assert global_status_variable(variable-list)
#pragma assert non_zero(constant-expression) string-literal
Descriptions follow.
The #pragma assert func_attrs directive:
The identifier-list is a list of function identifiers about
which the compiler can make assertions. If more than one
identifier is specified, separate them by commas.
The function-assertions specify the assertions for the compiler
to make about the functions. Specify one or more of the
following, separating multiple assertions with whitespace:
noreturn
The compiler can assert that any call to the routine will
never return.
nocalls_back
The compiler can assert that no routine in the source
module will be called before control is returned from this
function.
nostate
The compiler can assert that the value returned by the
function and any side-effects the function might have are
determined only by the function's arguments. If a
function is marked as having both noeffects and nostate,
the compiler can eliminate redundant calls to the
function.
noeffects
The compiler can assert that any call to this function
will have no effect except to set the return value of the
function. If the compiler determines that the return
value from a function call is never used, it can remove
the call.
file_scope_vars(option)
The compiler can make assertions about how a function will
access variables declared at file scope (with either
internal or external linkage).
The file_scope_vars option is one of the following:
o none - The function will not read nor write to any
file-scope variables except those whose type is
volatile or those listed in a #pragma assert
global_status_variable.
o noreads - The function will not read any file-scope
variables except those whose type is volatile or those
listed in a #pragma assert global_status_variable.
o nowrites - The function will not write to any
file-scope variables except those whose type is
volatile or those listed in a #pragma assert
global_status_variable.
format (<style>, <format-index>, <first-to-check-index>)
Asserts to the compiler that this function takes printf-
or scanf-style arguments to be type-checked against a
format string. Specify the parameters as follows:
o <style> -- PRINTF or SCANF.
This determines how the format string is interpreted.
o <format-index> -- {1|2|3|...}
This specifies which argument is the format-string
argument (starting from 1).
o <first-to-check-index> -- {0|1|2|...}
This is the number of the first argument to check
against the format string. For functions where the
arguments are not available to be checked (such as
vprintf), specify the third parameter as 0. In this
case, the compiler only checks the format string for
consistency.
The #pragma assert global_status_variable directive:
Use the #pragma assert global_status_variable(variable-list)
form of the pragma to specify variables that are to be
considered global status variables, which are exempt from any
assertions given to functions by #pragma assert func_attrs
file_scope_vars directives.
The variable-list is a list of variables.
The #pragma assert non_zero directive:
When the compiler encounters this directive, it evaluates the
constant-expression. If the expression is zero, the compiler
generates a message that contains both the specified
string-literal and the compile-time constant-expression. For
example:
#pragma assert non_zero(sizeof(a) == 12) "a is the wrong size"
In this example, if the compiler determines that the sizeof a
is not 12, the following diagnostic message is output:
CC-W-ASSERTFAIL, The assertion "(sizeof(a) == 12)" was not
true. a is the wrong size.
Unlike the #pragma assert options func_attrs and
global_status_variable, #pragma assert non_zero can appear
either inside or outside a function body. When used inside a
function body, the pragma can appear wherever a statement can
appear, but the pragma is not treated as a statement. When
used outside a function body, the pragma can appear anywhere a
declaration can appear, but the pragma is not treated as a
declaration.
Because macro replacement is not performed on #pragma assert,
you might need to use the #pragma assert_m directive to obtain
the results you want. Consider the following program that
verifies both the size of a struct and the offset of one of its
elements:
#include <stddef.h>
typedef struct {
int a;
int b;
} s;
#pragma assert non_zero(sizeof(s) == 8) "sizeof assert failed"
#pragma assert_m non_zero(offsetof(s,b) == 4) "offsetof assert
failed"
Because offsetof is a macro, the second pragma must be #pragma
assert_m so that offsetof will expand correctly.
#pragma builtins[_m|_nm]
Enables the VSI C built-in functions that directly access
processor instructions.
The #pragma builtins directive is provided for VAX C
compatibility.
VSI C implements #pragma builtins by including the <builtins.h>
header file, and is equivalent to #include <builtins.h> on
OpenVMS systems.
This header file contains prototype declarations for the
built-in functions that allow them to be used properly. By
contrast, VAX C implemented this pragma with special-case code
within the compiler, which also supported a #pragma nobuiltins
preprocessor directive to turn off the special processing.
Because declarations cannot be "undeclared", VSI C does not
support #pragma nobuiltins. Furthermore, the names of all the
built-in functions use a naming convention defined by ANSI C to
be in a namespace reserved to the C language implementation.
#pragma dictionary[_m|_nm]
Allows you to extract CDD data definitions and include these
definitions in your program.
The ANSI C compliant #pragma dictionary directive is equivalent
to the VAX C compatible #dictionary directive, but is supported
in all compiler modes. (The #dictionary directive is retained
for compatibility and is supported only when compiling with the
/STANDARD=VAXC qualifier.)
Syntax:
#pragma dictionary "cdd_path" [null_terminate]
[name(structure_name)] [text1_to_array | text1_to_char]
The cdd_path is a character string that gives the path name of
the CDD record. It can also be a macro that resolves to such a
character string.
The optional null_terminate keyword can be used to specify that
all string data types should be null-terminated.
The optional name() can be used to supply an alternate tag name
or a declarator, struct_name for the outer level of a CDD
structure.
The optional text1_to_char keyword forces the CDD type "text"
to be translated to char, rather than "array of char" if the
size is 1. This is the default if null_terminate is not
specified.
The optional text1_to_array keyword forces the CDD type "text"
to be translated to type "array of char" even when the size
is 1. This is the default when null_terminate is specified.
#pragma environment[_m|_nm]
Sets, saves, or restores the states of context pragmas. This
directive protects include files from contexts set by
encompassing programs, and protects encompassing programs from
contexts that could be set in header files that they include.
The #pragma environment directive affects the following
pragmas:
o #pragma extern_model
o #pragma extern_prefix
o #pragma member_alignment
o #pragma message
o #pragma names
o #pragma pointer_size
o #pragma required_pointer_size
Syntax:
#pragma environment command_line
#pragma environment header_defaults
#pragma environment restore
#pragma environment save
command_line
Sets, as specified on the command line, the states of all
the context pragmas. You can use this pragma to protect
header files from environment pragmas that take effect
before the header file is included.
header_defaults
Sets the states of all the context pragmas to their
default values. This is almost equivalent to the
situation in which a program with no command-line options
and no pragmas is compiled, except that this pragma sets
the pragma message state to #pragma nostandard, as is
appropriate for header files.
save
Saves the current state of every pragma that has an
associated context.
restore
Restores the current state of every pragma that has an
associated context.
#pragma extern_model[_m|_nm]
Controls the compiler's interpretation of objects that have
external linkage. This pragma lets you choose the global
symbol model to be used for externs.
Syntax:
#pragma extern_model common_block [attr[,attr]...]
#pragma extern_model relaxed_refdef [attr[,attr]...]
#pragma extern_model strict_refdef "name" [attr[,attr]...]
#pragma extern_model strict_refdef
#pragma extern_model globalvalue
#pragma extern_model save
#pragma extern_model restore
The default model on VSI C is #pragma relaxed_refdef noshr.
This is different from the model used by VAX C, which is common
block, shr.
The [attr[,attr]...] are optional psect attribute
specifications chosen from the following (at most one from each
line):
o gbl lcl (Not allowed with relaxed_refdef)
o shr noshr
o wrt nowrt
o pic nopic (Not meaningful for Alpha)
o ovr con
o rel abs
o exe noexe
o vec novec
o noreorder (named strict_refdef only)
o natalgn (named strict_refdef only)
o 0 byte 1 word 2 long 3 quad 4 octa 5 6 7 8 9 10 11 12 13 14
15 16 page
See the HP C User's Guide for more information on the #pragma
extern_model directive.
#pragma extern_prefix[_m|_nm]
Controls the compiler's synthesis of external names, which the
linker uses to resolve external name requests.
When you specify #pragma extern_prefix with a string argument,
the compiler prepends the string to all external names
produced by the declarations that follow the pragma
specification.
This pragma is useful for creating libraries where the
facility code can be attached to the external names in the
library.
Syntax:
#pragma extern_prefix "string" [(id[,id]...)]
#pragma extern_prefix {NOCRTL|RESTORE_CRTL} (id[,id]...)
#pragma extern_prefix save
#pragma extern_prefix restore
Where "string" prepends the quoted string to external names in
the declarations that follow the pragma specification.
You can also specify an extern prefix for specific identifiers
using the optional list [(<emphasis>(id)[,<emphasis>(id)]...)].
The NOCRTL and RESTORE_CRTL keywords control whether or not the
compiler applies its default RTL prefixing to the names
specified in the id-list, required for this form of the pragma.
The effect of NOCRTL is like that of the EXCEPT=keyword of the
/PREFIX_LIBRARY_ENTRIES command-line qualifier. The effect of
RESTORE_CRTL is to undo the effect of a #pragma extern_prefix
NOCRTL or a /PREFIX=EXCEPT= on the command line.
The save and restore keywords can be used to save the current
pragma prefix string and to restore the previously saved pragma
prefix string, respectively.
The default external prefix, when none has been specified by a
pragma, is the null string.
#pragma function[_m|_nm]
Specifies that calls to the specified functions are not
intrinsic but are, in fact, function calls. This pragma has
the opposite effect of #pragma intrinsic.
Syntax:
#pragma function[_m|_nm] (function1[, function2, ...])
#pragma include_directory[_m|_nm]
The effect of each #pragma include_directory is as if its
string argument (including the quotes) were appended to the
list of places to search that is given its initial value by the
/INCLUDE_DIRECTORY qualifier, except that an empty string is
not permitted in the pragma form.
Syntax:
#pragma include_directory <string-literal>
This pragma is intended to ease DCL command-line length
limitations when porting applications from POSIX-like
environments built with makefiles containing long lists of -I
options specifying directories to search for headers. Just as
long lists of macro definitions specified by the /DEFINE
qualifier can be converted to #define directives in a source
file, long lists of places to search specified by the
/INCLUDE_DIRECTORY qualifier can be converted to #pragma
include_directory directives in a source file.
Note that the places to search, as described in the help text
for the /INCLUDE_DIRECTORY qualifier, include the use of
POSIX-style pathnames, for example "/usr/base". This form can
be very useful when compiling code that contains POSIX-style
relative pathnames in #include directives. For example,
#include <subdir/foo.h> can be combined with a place to search
such as "/usr/base" to form "/usr/base/subdir/foo.h", which
will be translated to the filespec "USR:[BASE.SUBDIR]FOO.H"
This pragma can appear only in the main source file or in the
first file specified on the /FIRST_INCLUDE qualifier. Also, it
must appear before any #include directives.
#pragma [no]inline[_m|_nm]
Expands function calls inline. The function call is replaced
with the function code itself.
Syntax:
#pragma inline (id,...)
#pragma noinline (id,...)
If a function is named in an inline directive, calls to that
function will be expanded as inline code, if possible.
If a function is named in a noinline directive, calls to that
function will not be expanded as inline code.
If a function is named in both an inline and a noinline
directive, an error message is issued.
For calls to functions named in neither an inline nor a
noinline directive, DEC C expands the function as inline code
whenever appropriate as determined by a platform-specific
algorithm.
#pragma intrinsic[_m|_nm]
Specifies that calls to the specified functions are intrinsic
(that is, handled internally by the compiler, allowing it to
generate inline code, move or eliminate calls, or do various
other optimizations). This pragma is only valid for functions
that are known to the compiler.
Syntax:
#pragma intrinsic (function1[, function2, ...])
#pragma linkage[_m|_nm]
Specifies special linkage types for function calls. This
pragma is used with the #pragma use_linkage directive, which
associates a previously defined special linkage with a
function.
Syntax:
#pragma linkage linkage-name = (characteristics)
#pragma linkage_ia64 linkage-name = (characteristics)
On I64 systems, these two formats behave differently:
o The #pragma linkage_ia64 format requires I64 register names
be specified.
o The #pragma linkage format requires Alpha register names be
specified, which are automatically mapped, where possible,
to specific I64 registers.
The two formats are further described after the description of
the characteristics.
The characteristics specify information about where parameters
will be passed, where the results of the function are to be
received, and what registers are modified by the function call.
Specify these characteristics as a parenthesized list of items
of the following forms:
parameters (register-list)
result (simple-register-list)
preserved (simple-register-list)
nopreserve (simple-register-list)
notused (simple-register-list)
notneeded (ai, lp)
standard_linkage
You can supply the option keywords in any order.
Description of Options:
simple-register-list
A comma-separated list of register names, either Rn or Fn.
Example:
nopreserve(F5, F6)
For the #pragma linkage format, valid registers for the
preserved, nopreserve, and notused options include
general-purpose registers R0 through R30, and
floating-point registers F0 through F30.
Valid registers for the result and parameters options
include general-purpose registers R0 through R25, and
floating-point registers F0 through F30.
For the #pragma linkage_ia64 format, see below for an
explanation of register usage.
register-list
Similar to a simple-register-list except that it can
contain parenthesized sublists. Use the register-list to
describe arguments and function result types that are
structs, where each member of the struct is passed in a
single register. Example:
parameters(R5, (F5, F6))
parameters
Use this option to pass arguments to the parameters of a
routine in specific registers.
result
Use this option to specify the register to be used to
return the value for the function. If a function has a
return type of void, do not specify the result option as
part of the linkage.
preserved
A preserved register contains the same value after a call
to the function as it did before the call.
nopreserve
A nopreserve register does not necessarily contain the
same value after a call to the function as it did before
the call.
notused
A notused register is not used in any way by the called
function.
notneeded
Indicates that certain items are not needed by the
routines using this linkage. Valid options are:
AI -- Specifies that the Argument Information
register (R25) does not need to be set up when
calling the specified functions.
LP -- Specifies that the Linkage Pointer register
does not need to be set up when calling the specified
functions. Note that for I64 systems, there is no
linkage pointer, so this setting is accepted but does
not change the behavior of the pragma.
standard_linkage
Tells the compiler to use the standard linkage appropriate
to the target platform. This can be useful to confine
conditional compilation to the pragmas that define
linkages, without requiring the corresponding #pragma
use_linkage directives to be conditionally compiled as
well.
If the standard_linkage keyword is specified, it must be
the only option in the parenthesized list following the
linkage name. For example:
#pragma linkage special1 = (standard_linkage)
If the standard_linkage keyword is not specified, you can
supply the parameters, result, preserved, nopreserve, and
notused options in any order, separated by commas.
Description of the two formats of this pragma:
The #pragma linkage_ia64 format of this preprocessor directive
requires register names to be specified in terms of an OpenVMS
I64 system. The register names are never mapped to a different
architecture. This form of the pragma always produces an error
if encountered on a different architecture.
For this format of the pragma, valid registers for the
preserved, nopreserve, notused, parameters, and result options
are:
o Integer registers R3 through R12 and R19 through R31
o Floating-point registers F2 through F31
In addition, the parameters and result options also permit
integer registers R32 through R39 to be specified, according to
the following convention. On IA64, the first eight integer
input/output slots are allocated to stacked registers, and thus
the calling routine refers to them using different names than
the called routine. The convention for naming these registers
in either the parameters or result option of a #pragma
linkage_ia64 directive is always to use the hardware names as
they would be used within the called routine: R32 through R39.
The compiler automatically compensates for the fact that within
the calling routine these same registers are designated using
different hardware names.
The #pragma linkage format of this preprocessor directive
accepts Alpha register names and conventions and automatically
maps them, where possible, to specific I64 registers. So
whenever VSI C for I64 encounters a #pragma linkage directive,
it attempts to map the Alpha registers specified in the linkage
to corresponding I64 registers, and emits a SHOWMAPLINKAGE
informational message showing the I64 specific form of the
directive, #pragma linkage_ia64, with the I64 register names
that replaced the Alpha register names. The SHOWMAPLINKAGE
message is suppressed under the #pragma nostandard directive,
normally used within system header files.
Code compiled on I64 systems that deliberately relies on the
register mapping performed by #pragma linkage should either
ignore the SHOWMAPLINKAGE informational, or disable it.
The following shows the mapping that VSI C applies to the Alpha
integer register names used in #pragma linkage format
directives when they are encountered on an I64 system. Note
that the six standard parameter registers on Alpha (R16-R21)
are mapped to the first six (of eight) standard parameter
registers on I64 systems, which happen to be stacked registers:
Integer Register Mapping:
Alpha -> I64 Alpha -> I64
R0 -> R8 R16 -> R32 *
R1 -> R9 R17 -> R33 *
R2 -> R28 R18 -> R34 *
R3 -> R3 R19 -> R35 *
R4 -> R4 R20 -> R36 *
R5 -> R5 R21 -> R37 *
R6 -> R6 R22 -> R22
R7 -> R7 R23 -> R23
R8 -> R26 R24 -> R24
R9 -> R27 R25 -> R25
R10 ->R10 R26 - no mapping
R11 ->R11 R27 - no mapping
R12 ->R30 R28 - no mapping
R13 ->R31 R29 -> R29
R14 ->R20 R30 -> R12
R15 ->R21 R31 -> R0
* In parameters or result; else ignored
The following shows the mapping that VSI C applies to the Alpha
floating-point register names used in #pragma linkage
directives when they are encountered on an I64 system:
Floating-Point Register Mapping:
Alpha -> I64 Alpha -> I64
F0 -> F8 F16 -> F8
F1 -> F9 F17 -> F9
F2 -> F2 F18 -> F10
F3 -> F3 F19 -> F11
F4 -> F4 F20 -> F12
F5 -> F5 F21 -> F13
F6 -> F16 F22 -> F22
F7 -> F17 F23 -> F23
F8 -> F18 F24 -> F24
F9 -> F19 F25 -> F25
F10 ->F6 F26 - F26
F11 ->F7 F27 - F27
F12 ->F20 F28 - F28
F13 ->F21 F29 -> F29
F14 ->F14 F30 -> F30
F15 ->F15
Mapping Diagnostics:
In some cases, the HP C compiler on Alpha systems silently
ignores linkage registers if, for example, a standard parameter
register like R16 is specified in a preserved option. When you
compile on an I64 system, this situation emits an MAPREGIGNORED
informational message, and the SHOWMAPLINKAGE output might not
be correct. If there is no valid mapping to I64 registers, the
NOMAPPOSSIBLE error message is output. There are two special
situations that can arise when floating-point registers are
specified in a linkage:
o Only IEEE-format values are passed in floating-point
registers under the OpenVMS Calling Standard for I64: VAX
format values are passed in integer registers. Therefore,
a compilation that specifies /FLOAT=D_FLOAT or
/FLOAT=G_FLOAT produces an error for any linkage that
specifies floating-point registers. Note that this
includes use in options that do not involve passing values,
such as the preserved and notused options.
o The mapping of floating-point registers is many-to-one in
two cases:
- Alpha registers F0 and F16 both map to I64 register F8
- Alpha F1 and F17 both map to I64 register F9.
A valid Alpha linkage may well specify uses for both F0 and
F16, and/or both F1 and F17. Such a linkage cannot be
mapped on an I64 system. But because of the way this
situation is detected, the MULTILINKREG warning message
that is produced can only identify the second occurrence of
an Alpha register that got mapped to the same I64 register
as some previous Alpha register. The actual pair of Alpha
registers in the source is not identified, and so the
message can be confusing. For example, an option like
preserved(F1,F17) gets a MULTILINKREG diagnostic saying
that F17 was specified more than once.
#pragma [no]member_alignment[_m|_nm]
Tells the compiler to align structure members on the next
boundary appropriate to the type of the member rather than the
next byte. For example, a long variable is aligned on the next
longword boundary; a short variable on the next word boundary.
Syntax:
#pragma nomember_alignment [base_alignment]
#pragma member_alignment [save | restore]
The optional base_alignment parameter can be used with #pragma
nomember_alignment to specify the base alignment of the
structure. Use one of the following keywords to specify the
base_alignment:
o BYTE (1 byte)
o WORD (2 bytes)
o LONGWORD (4 bytes)
o QUADWORD (8 bytes)
o OCTAWORD (16 bytes)
The optional save and restore keywords can be used to save the
current state of the member_alignment and to restore the
previous state, respectively. This feature is necessary for
writing header files that require member_alignment or
nomember_alignment, or that require inclusion in a
member_alignment that is already set.
#pragma message[_m|_nm]
Controls the issuance of individual diagnostic messages or
groups of messages. Use of this pragma overrides any
command-line options that may affect the issuance of messages.
Syntax:
#pragma message option1 message-list
#pragma message option2
#pragma message (quoted-string)
where option1 is:
disable Suppresses the issuance of the indicated
messages.
Only messages of severity Warning (W) or
Information (I) can be disabled. If the
message has severity of Error (E) or
Fatal (F), it is issued regardless of
any attempt to disable it.
enable Enables the issuance of the indicated
messages.
emit_once Emits the specified messages only once
per compilation.
emit_always Emits the specified messages at every
occurrence of the condition.
error Sets the severity of each message in the
message-list to Error.
fatal Sets the severity of each message on the
message-list to Fatal.
informational Sets the severity of each message in the
message-list to Informational.
warning Sets the severity of each message in the
message-list to Warning.
The message-list can be any one of the following:
o A single message identifier (within parentheses or not).
o A single message-group name (within parentheses or not).
Message-group names are:
ALL All the messages in the compiler
ALIGNMENT Messages about unusual or inefficient
data alignment.
C_TO_CXX Messages reporting the use of C features
that would be invalid or have a
different meaning if compiled by a C++
compiler.
CDD Messages about CDD (Common Data
Dictionary) support.
CHECK Messages reporting code or practices
that, although correct and perhaps
portable, are sometimes considered
ill-advised because they can be
confusing or fragile to maintain. For
example, assignment as the test
expression in an "if" statement.
NOTE: The check group gets defined by
enabling level5 messages.
DEFUNCT Messages reporting the use of obsolete
features: ones that were commonly
accepted by early C compilers but were
subsequently removed from the language.
NEWC99 Messages reporting the use of the new
C99 Standard features.
NOANSI Messages reporting the use of non-ANSI
Standard features. The NOANSI message
group is a synonym for NOC89. Also see
message groups NEWC99, NOC89, NOc99.
NOC89 Messages reporting the use of non-C89
Standard features.
NOC99 Messages reporting the use of non-C99
Standard features.
OBSOLESCENT Messages reporting the use of features
that are valid in ANSI Standard C, but
which were identified in the standard as
being obsolescent and likely to be
removed from the language in a future
version of the standard.
OVERFLOW Messages that report assignments and/or
casts that can cause overflow or other
loss of data significance.
PERFORMANCE Messages reporting code that might
result in poor run-time performance.
PORTABLE Messages reporting the use of language
extensions or other constructs that
might not be portable to other compilers
or platforms.
PREPROCESSOR Messages reporting questionable or
non-portable use of preprocessing
constructs.
QUESTCODE Messages reporting questionable coding
practices. Similar to the check group,
but messages in this group are more
likely to indicate a programming error
rather than just a non-robust style.
Enabling the QUESTCODE group provides
lint-like checking.
RETURNCHECKS Messages related to function return
values.
UNINIT Messages related to using uninitialized
variables.
UNUSED Messages reporting expressions,
declarations, header files, CDD records,
static functions, and code paths that
are not used.
Note, however, that unlike any other
messages, these messages must be enabled
on the command line
(/WARNINGS=ENABLE=UNUSED) to be
effective.
o A single message-level name (within parentheses or not).
Note: There is a core of very important compiler messages
that are enabled by default, regardless of anything
specified with /WARNINGS or #pragma message. Referred to as
message level 0, it includes all messages issued in header
files, and comprises what is known as the nostandard group.
All other message levels add additional messages to this
core of enabled messages.
You cannot disable level 0. However, you can disable
individual messages in level 0 that are not errors or
fatals.
Message-level names are:
LEVEL1 Important messages. These are less
important than level 0, because messages
in this group are not displayed if #pragma
nostandard is active.
LEVEL2 Moderately important messages. This level
is used to introduce new messages that
will be output in the DIGITAL UNIX V4.0
release. LEVEL2 is the default for
DIGITAL UNIX and Tru64 UNIX platforms.
LEVEL3 Less important messages. In general,
these are the messages output by default
in DEC C Version 5.5 for OpenVMS Systems.
LEVEL3 is the default message level for
VSI C for OpenVMS systems.
LEVEL4 Useful check/portable messages.
LEVEL5 Not so useful check/portable messages.
LEVEL6 All messages in LEVEL5 plus additional
"noisy" messages.
Enabling a level also enables all the messages in the levels
below it. So enabling LEVEL3 messages also enables messages
in LEVEL2 and LEVEL1.
Disabling a level also disables all the messages in the
levels above it. So disabling LEVEL4 messages also disables
messages in LEVEL5 and LEVEL6.
o A comma-separated list of message identifiers, group names,
and messages levels, freely mixed, enclosed in parentheses.
option2 is:
save -- saves the current state of which messages are
enabled and disabled.
restore -- restores the previous state of which messages
are enabled and disabled.
The save and restore options are useful primarily within header
files.
The #pragma message (quoted-string) form outputs the
quoted-string as a compiler message. This form of the pragma is
subject to macro replacement. For example, the following is
valid:
#pragma message ("Compiling file " __FILE__)
#pragma module[_m|_nm]
The ANSI C compliant #pragma module directive is equivalent to
the VAX C compatible #module directive, but is supported in all
compiler modes. (The #module directive is retained for
compatibility and is supported only when compiling with the
/STANDARD=VAXC qualifier.) The #pragma module directive is
specific to VSI C for OpenVMS Systems and is not portable.
Use the #pragma module directive to change the
system-recognized module name and version number. You can find
the module name and version number in the compiler listing file
and the linker load map.
Syntax:
#pragma module identifier identifier
#pragma module identifier string
The first parameter must be a valid VSI C identifier. It
specifies the module name to be used by the linker. The second
parameter specifies the optional identification that appears on
listings and in the object file. It must be either a valid VSI
C identifier of 31 characters or less, or a character-string
constant of 31 characters or less.
Only one #pragma module directive can be processed per
compilation unit, and that directive must appear before any C
language text. The #pragma module directive can follow other
directives, such as #define, but it must precede any function
definitions or external data definitions.
#pragma names[_m|_nm]
Provides the same kinds of control over the mapping of external
identifiers' object-module symbols as does the /NAMES
command-line qualifier, and it uses the same keywords. But as
a pragma, the controls can be applied selectively to regions of
declarations.
This pragma should only be used in header files and is intended
for use by developers who supply libraries and/or header files
to their customers.
The pragma has a save/restore stack that is also managed by
#pragma environment, and so it is well-suited for use in header
files. The effect of #pragma environment header_defaults is to
set NAMES to "uppercase,truncated", which is the compiler
default.
Syntax:
#pragma names <stack-option>
#pragma names <case-option>
#pragma names <length-option>
Where
<stack-option> is one of:
o save - save the current names state
o restore - restore a saved names state
<case-option> is one of:
o uppercase - uppercase external names
o as_is - do not change case
<length-option> is one of:
o truncated - truncate at 31 characters
o shortened - shorten to 31 using CRC
#pragma optimize[_m|_nm]
Sets the optimization characteristics of function definitions
that follow the directive. It allows optimization-control
options that are normally set on the command line for the
entire compilation to be specified in the source file for
individual functions.
Syntax:
#pragma optimize <settings>
#pragma optimize save
#pragma optimize restore
#pragma optimize command_line
Where <settings> is any combination of the following:
o <level settings>
Set the optimization level. Specify as:
level=n
Where n is an integer from 0 to 5.
o <unroll settings>
Control loop unrolling. Specify as:
unroll=n
Where n is a nonnegative integer.
o <ansi-alias settings>
Control ansi-alias assumptions. Specify one of the following:
ansi_alias=on
ansi_alias=off
o <intrinsic settings>
Control recognition of intrinsics. Specify one of the
following:
intrinsics=on
intrinsics=off
Use the save, restore, and command_line keywords as follows:
o save -- Saves the current pointer size
o restore -- Restores the current pointer size to its last
saved state
o command_line -- Sets the optimization settings to what was
specified on the command line
Example:
#pragma optimize level=5 unroll=6
Usage Notes:
o If the level=0 clause is present, it must be the only
clause present.
o The #pragma optimize directive must appear at file scope,
outside any function body.
o The #pragma environment save and restore operations include
the optimization state.
o The #pragma environment command_line directive resets the
optimization state to that specified on the command line.
o If #pragma optimize does not specify a setting for one of
the optimization states, that state remains unchanged.
o When a function definition is encountered, it is compiled
using the optimization settings that are current at that
point in the source.
o When a function is compiled under level=0, the compiler
will not inline that function. In general, when functions
are inlined, the inlined code is optimized using the
optimization controls in effect at the call site instead of
using the optimization controls specified for the function
being inlined.
o When the OpenVMS command line specifies /NOOPT (or
/OPTIMIZE=LEVEL=0), the #pragma optimize directive has no
effect (except that its arguments are still validated).
#pragma pack[_m|_nm]
Specifies the byte boundary for packing members of C
structures.
Syntax:
#pragma pack [n]
The n specifies the new alignment restriction in bytes:
1 - align to byte
2 - align to word
4 - align to longword
8 - align to quadword
16 - align to octaword
A structure member is aligned to either the alignment specified
by #pragma pack or the alignment determined by the size of the
structure member, whichever is smaller. For example, a short
variable in a structure gets byte-aligned if #pragma pack 1 is
specified. If #pragma pack 2, 4, or 8 is specified, the short
variable in the structure gets aligned to word.
When #pragma pack is specified without a value or with a value
of 0, packing reverts to that specified by the
/[NO]MEMBER_ALIGNMENT qualifier setting (either explicitly
specified or by default) on the command line. Note that when
specifying #pragma pack without a value, you must use
parentheses: #pragma pack ().
#pragma pointer_size[_m|_nm]
Controls whether pointers are 32-bit pointers or 64-bit
pointers.
Syntax:
#pragma pointer_size keyword
Where keyword is one of the following:
o short -- 32-bit pointer
o long -- 64-bit pointer
o system_default -- 32-bit pointers on OpenVMS systems;
64-bit pointers on Tru64 UNIX systems
o save -- Saves the current pointer size
o restore -- Restores the current pointer size to its last
saved state
This directive is enabled only when the /POINTER_SIZE command-line
qualifier is specified. Otherwise, #pragma pointer_size has the
same effect as #pragma required_pointer_size.
#pragma required_pointer_size[_m|_nm]
Intended for use by developers of header files to control
pointer size within header files.
Syntax:
#pragma required_pointer_size keyword
Where keyword is one of the following:
o short -- 32-bit pointer
o long -- 64-bit pointer
o system_default -- 32-bit pointers on OpenVMS systems;
64-bit pointers on Tru64 UNIX systems
o save -- Saves the current pointer size
o restore -- Restores the current pointer size to its last
saved state
This directive is always enabled, even if the /POINTER_SIZE
command-line qualifier is omitted. Otherwise, #pragma
required_pointer_size has the same effect as #pragma pointer_size.
#pragma [no]standard[_m|_nm]
Directs the compiler to define regions of source code where
portability diagnostics are not to be issued.
Use #pragma nostandard to suppress diagnostics about non-ANSI C
extensions, regardless of the /STANDARD qualifier specified,
until a #pragma standard directive is encountered.
Use #pragma standard to reinstate the setting of the /STANDARD
qualifier that was in effect before before the last #pragma
nostandard was encountered.
Every #pragma standard directive must be preceded by a
corresponding #pragma nostandard directive.
Note that this pragma does not change the current mode of the
compiler or enable any extensions not already supported in that
mode.
#pragma unroll[_m|_nm]
Directs the compiler to unroll the for loop that follows it by
the number of times specified in the unroll_factor argument.
The #pragma unroll directive must be followed by a for
statement.
Syntax:
#pragma unroll (unroll_factor)
The unroll_factor is an integer constant in the range 0 to 255.
If a value of 0 is specified, the compiler ignores the
directive and determines the number of times to unroll the loop
in its normal way. A value of 1 prevents the loop from being
unrolled. The directive applies only to the for loop that
follows it, not to any subsequent for loops.
#pragma use_linkage[_m|_nm]
Associates a special linkage, defined by the #pragma linkage
directive, with the specified functions.
Syntax:
#pragma use_linkage linkage-name (routine1, routine2, ...)
The linkage-name is the name of a linkage previously defined by
the #pragma linkage directive.
The parenthesized list contains the names of functions you want
to associated with the named linkage.
The list can also contain typedef names of function type, in
which case functions or pointers to functions declared using
that type will have the specified linkage.
8.10 – #undef
The #undef directive cancels a previously defined macro
replacement. Any other macro replacements that occurred before the
#undef directive remain.
The #undef directive has the following syntax:
#undef identifier
9 – Predefined Macros
In addition to the ANSI-compliant, implementation-independent macros described in the HP C Language Reference Manual, The VSI C compiler provides the following predefined macros:
9.1 – System Identification Macros
Each implementation of the VSI C compiler automatically defines
macros that you can use to identify the system on which the program
is running. These macros can assist in writing code that executes
conditionally, depending on the architecture or operating system on
which the program is running.
The following table lists the traditional and new spellings of
these predefined macro names for VSI C on OpenVMS systems. Both
spellings are defined for each macro unless ANSI C mode is in
effect (/STANDARD=ANSI89), in which case only the new spellings are
defined.
Traditional spelling New spelling
vms __vms
VMS __VMS
vms_version __vms_VERSION
VMS_VERSION __VMS_VERSION
__VMS_VER
__DECC_VER
__DECCXX_VER
vaxc __vaxc
VAXC __VAXC
vax11c __vax11C
VAX11C __VAX11C
--- __DECC
--- __STDC__
__STDC_HOSTED__
__STDC_VERSION__
__STDC_ISO_10646__
__MIA
On OpenVMS I64 Systems, VSI C also supports the following
predefined system identification macro names in all compiler modes:
__ia64
__ia64__
__32BITS
__INITIAL_POINTER_SIZE
Predefined macros (with the exception of __STDC_VERSION__,
__STDC_ISO_10646__, vms_version, VMS_VERSION, __vms_version,
__VMS_VERSION, and __INITIAL_POINTER_SIZE) are defined as 1 or 0,
depending on the system you're compiling on (VAX or Alpha
processor), the compiler defaults, and the qualifiers used. For
example, if you compiled using G_floating format, then __D_FLOAT
and __IEEE_FLOAT (Alpha processors only) are predefined to be 0,
and __G_FLOAT is predefined as if the following were included
before every compilation unit:
#define __G_FLOAT 1
These macros can assist in writing code that executes
conditionally. They can be used in #elif, #if, #ifdef, and #ifndef
directives to separate portable and nonportable code in a VSI C
program. The vms_version, VMS_VERSION, __vms_version, and
__VMS_VERSION macros are defined with the value of the OpenVMS
version on which you are running (for example, Version 6.0).
The __STDC__ macro is defined to 1 for /STANDARD options ANSI89,
C99, LATEST and MIA. It is defined to 2 for /STANDARD=RELAXED and
to 0 for /STANDARD=MS. It is not defined for /STANDARD options
VAXC and COMMON.
The __STDC_HOSTED__ macro is defined to 1 for /STANDARD=c99 and
/STANDARD=LATEST. It is not defined for all other /STANDARD
keywords.
The __STDC_VERSION__ macro is defined to 199901L for /STANDARD
keywords C99, LATEST, RELAXED, MS, PORTABLE. It is defined to
199409L when the ISOC94 keyword is specified alone or with the
ANSI89, MIA, RELAXED, MS, PORTABLE, or COMMON modes. The macro is
undefined for the VAXC keyword or for keywords ANSI89, MIA, or
COMMON without ISOC94 specified.
The __STDC_ISO_10646__ macro evaluates to an integer constant of
the form yyyymmL (for example, 199712L), intended to indicate that
values of type wchar_t are the coded representations of the
characters defined by ISO/IEC 10646, along with all amendments and
technical corrigenda as of the specified year and month.
9.2 – Compiler Mode Macros
The following predefined macros are defined as 1 if the corresponding compiler mode is selected (Otherwise, they are undefined): __DECC_MODE_STRICT ! /STANDARD=ANSI89 __DECC_MODE_RELAXED ! /STANDARD=RELAXED __DECC_MODE_VAXC ! /STANDARD=VAXC __DECC_MODE_COMMON ! /STANDARD=COMMON __STDC__ ! /STANDARD=ANSI89, /STANDARD=RELAXED __STDC_VERSION__ ! /STANDARD=ISOC94 __MS ! /STANDARD=MS
9.3 – Floating Point Macros
VSI C automatically defines the following predefined macros pertaining to the format of floating-point variables. You can use them to identify the format with which you are compiling your program: __D_FLOAT __G_FLOAT __IEEE_FLOAT _IEEE_FP __X_FLOAT
9.4 – RTL Standards Macros
VSI C defines the following macros that you can explicitly define (using the /DEFINE qualifier or the #define preprocessor directive) to control which VSI C RTL functions are declared in header files and to obtain standards conformance checking: _XOPEN_SOURCE_EXTENDED _XOPEN_SOURCE _POSIX_C_SOURCE _ANSI_C_SOURCE _VMS_V6_SOURCE _DECC_V4_SOURCE __BSD44_CURSES __VMS_CURSES _SOCKADDR_LEN
9.5 – HIDE FORBIDDEN NAMES
The ANSI C standard specifies exactly what identifiers in the
normal name space are declared by the standard header files. A
compiler is not free to declare additional identifiers in a header
file unless the identifiers follow defined rules (the identifier
must begin with an underscore followed by an uppercase letter or
another underscore).
When you compile with VSI C using any values of /STANDARD that set
strict C standard conformance (ANSI89, MIA, C99, and LATEST),
versions of the standard header files are included that hide many
identifiers that do not follow the rules. The header file
<stdio.h>, for example, hides the definition of the macro TRUE.
The compiler accomplishes this by predefining the macro
__HIDE_FORBIDDEN_NAMES for the above-mentioned /STANDARD values.
You can use the command line qualifier
/UNDEFINE="__HIDE_FORBIDDEN_NAMES" to prevent the compiler from
predefining this macro, thus including macro definitions of the
forbidden names.
The header files are modified to only define additional VAX C names
if __HIDE_FORBIDDEN_NAMES is undefined. For example, <stdio.h>
might contain the following:
#ifndef __HIDE_FORBIDDEN_NAMES
#define TRUE 1
#endif
9.6 – CC$gfloat
When you compile using the /G_FLOAT qualifier, CC$gfloat is defined as 1. When you compile without the /G_FLOAT qualifier, CC$gfloat is defined as 0. The CC$gfloat macro is provided for compatiblity with VAX C. The __G_FLOAT predefined macro should be used instead.
9.7 – DATE
The __DATE__ macro evaluates to a string specifying the date on
which the compilation started. The string presents the date in the
form "Mmm dd yyyy" The names of the months are those generated by
the asctime library function. The first d is a space if dd is less
than 10.
Example:
printf("%s",__DATE__);
9.8 – FILE
The __FILE__ macro evaluates to a string literal specifying the
file specification of the current source file.
Example:
printf("file %s", __FILE__);
9.9 – LINE
The __LINE__ macro evaluates to a decimal constant specifying the
number of the line in the source file containing the macro
reference.
Example:
printf("At line %d in file %s", __LINE__, __FILE__);
9.10 – TIME
The __TIME__ macro evaluates to a string specifying the time that
the compilation started. The time has the following format:
hh:mm:ss
Example:
printf("%s", __TIME__);
The value of this macro remains constant throughout the translation
unit.
10 – Predeclared Identifiers
10.1 – __func__
The __func__ predeclared identifier evaluates to a static array of
char, initialized with the spelling of the function's name. It is
visible anywhere within the body of a function definition.
Example:
void foo(void) {printf("%s\n", __func__);}
This function prints "foo".
11 – Statements
Statements are the executable instructions performed by the program. Statements produce values and control program flow. A group of statements enclosed in braces makes up a block. Any valid expression or declaration terminated by a semicolon is considered a statement. The statements that control program flow are described in further HELP frames. See also HELP CC LANGUAGE_TOPICS DECLARATION and HELP CC LANGUAGE_TOPICS PREPROCESSOR.
11.1 – break
The break statement terminates the immediately enclosing while, do,
for, or switch statement. Control passes to the statement
following the terminated statement.
Syntax:
break ;
11.2 – continue
The continue statement passes control to the test portion of the
immediately enclosing while, do, or for statement.
Syntax:
continue ;
In each of the following statements, a continue statement is
equivalent to "goto label;":
while (expression) { statement ... label: ; }
do { statement ... label: ; } while (expression);
for (expression; expression; expression)
{ statement ... label: ; }
The continue statement is not intended for switches. A continue
statement inside a switch statement inside a loop causes
reiteration of the loop.
11.3 – do
The do statement executes a statement one or more times, as long as
a stated condition expression is true.
Syntax:
do statement while ( expression ) ;
The do statement is executed at least once. The expression is
evaluated after each execution of the statement. If the expression
is not 0, the statement is executed again. The statement following
the do statement (the body of the do statement) is not optional;
the null statement (a lone semicolon) is provided for specifying a
do statement with an empty body.
11.4 – for
The for statement executes a statement zero or more times, with
three specified control expressions. Expression-1 is evaluated
only once, before the first iteration; expression-2 is evaluated
before every iteration; expression-3 is evaluated after every
iteration. The for loop terminates if, on evaluation, expression-2
is 0.
Syntax:
for ( [expression-1] ; [expression-2] ; [expression-3] )
statement
The for statement is equivalent to the following format:
expression-1;
while ( expression-2 ) { statement expression-3; }
You can omit any of the three expressions. If expression-2 is
omitted, the while condition is true.
11.5 – goto
The goto statement transfers control unconditionally to a labeled
statement.
Syntax:
goto identifier ;
The identifier must be a label located in the current function.
You may use goto to branch into a block, but no initializations are
performed on variables declared in the block.
11.6 – if
The if statement is a conditional statement. It can be written
with or without an else clause as follows:
if ( expression ) statement
if ( expression ) statement else statement
In both cases, the expression is evaluated, and if it is not 0, the
first statement is executed. If the else clause is included and
the expression is 0, the statement following else is executed
instead. In a series of if-else clauses, the else matches the most
recent else-less if.
11.7 – Labeled
Any statement can be preceded by a label prefix of the following
form:
identifier:
This declares the identifier as a label. The scope of such a
declaration is the current function. Labels are used only as the
targets of goto statements.
11.8 – Null
A null statement is a semicolon:
;
The null statement provides a null action -- for example, the body
of a for loop that takes no action:
for(i=0; i < ARRAYSIZE && x[i] == 5; i++)
;
11.9 – return
The return statement causes a return from a function, with or
without a return value.
Syntax:
return ;
return expression ;
The return value is undefined if not specified in a return
statement. If an expression is specified in the return statement,
it is evaluated and the value is returned to the calling function;
the value is converted, if necessary, to the type with which the
called function was declared. If a function does not have a return
statement, the effect (on reaching the end of the function) is the
same as with a return statement that does not specify an
expression. Functions declared as void may not contain return
statements specifying an expression.
11.10 – switch
The switch statement executes one or more of a series of cases,
based on the value of an integer expression.
Syntax:
switch ( expression ) body
The switch's body typically is a block, within which any statement
can be prefixed with one or more case labels as follows:
case constant-expression :
At most one statement in the body may have the label as follows:
default :
The switch expression is evaluated and compared to the cases. If
there is a case matching the expression's value, it is executed; if
not, the default case is executed. The switch is normally
terminated by a break, return, or goto statement in one of the
cases. If there is no matching case and no default, the body of
the switch statement is skipped.
11.11 – while
The while statement executes a statement 0 or more times, as long
as a stated condition is true.
Syntax:
while ( expression ) statement
The expression is evaluated before each execution, and the
statement is executed if the expression is not 0. The statement
following the parentheses (the body of the while statement) is not
optional; the null statement (a lone semicolon) is provided for
specifying a while statement with an empty body.
12 – Storage Classes
The storage class of a variable determines when its storage is allocated, whether its contents are preserved across different blocks or functions, and what link-time scope the variable has. Auto variables are allocated at run time. They are not preserved across functions. Auto is the default storage class for variables declared within a function. Extern variables are allocated at compile time. They are preserved across functions. There can be only 65,532 extern variables per program. Extern is the default storage class for variables declared outside a function. Globaldef, globalref, and globalvalue variables are allocated at compile time. They are preserved across functions. The number of global symbols is unlimited. Register variables are allocated at run time. They cannot be referenced from other separately compiled functions. Static variables are allocated at compile time. If externally declared, they retain their values across functions. If internally declared (inside of a function), they cannot be referenced from other functions; if control passes from the defining function, to other functions, and then passed back to the defining function, the variable retains its previous value and is not reinitialized.
13 – Type Qualifiers
Data-type qualifiers affect the allocation or access of data storage. The data-type qualifiers are const, volatile, __restrict, and __unaligned.
13.1 – const
The const data-type qualifier restricts access to stored data. If
you declare an object to be of type const, you cannot modify that
object. You can use the const data-type qualifier with the
volatile data-type qualifier or with any of the storage-class
specifiers or modifiers. The following example declares the
variable x to be a constant integer:
int const x;
13.2 – volatile
The volatile data-type qualifier prevents an object from being stored in a machine register, forcing it to be allocated in memory. This data-type qualifier is useful for declaring data that is to be accessed asynchronously. A device driver application often uses volatile data storage. Like const, you can specify the volatile data-type qualifier with any of the storage-class specifiers or modifiers with the exception of the register storage class.
13.3 – __restrict
The __restrict data-type qualifier is used to designate a pointer as pointing to a distinct object, thus allowing compiler optimizations to be made.
13.4 – __unaligned
This data-type qualifier is used in pointer definitions, indicating to the compiler that the data pointed to is not properly aligned on a correct address. (To be properly aligned, the address of an object must be a multiple of the size of the type. For example, two-byte objects must be aligned on even addresses.) When data is accessed through a pointer declared __unaligned, the compiler generates the additional code necessary to copy or store the data without causing alignment errors. It is best to avoid use of misaligned data altogether, but in some cases the usage may be justified by the need to access packed structures, or by other considerations.
14 – Storage Class Modifiers
The storage-class modifiers allow individual attributes of a
variable to change without changing the other default attributes
connected with a given storage class. Storage-class keywords and
storage-class modifiers can be specified in either order.
Syntax:
modifier storage_class_keyword identifier;
If you specify a storage-class modifier but not a storage class
keyword, the storage class defaults to extern.
14.1 – noshare
Noshare variables are assigned the PSECT attribute NOSHR. Noshare
variables may not be shared between processes. This modifier is
used when linking variables that are not to be shared within a
shareable image. You can use the noshare modifier with the
storage-class keywords static, [extern], globaldef, and
globaldef{"name"}.
14.2 – readonly
Readonly variables are assigned the PSECT attribute NOWRT and are
stored in the PSECT $READONLY$ which is a nonwritable data area.
Other programs can access the PSECT directly, but none of the
information can be overwritten. You can use the readonly modifier
with the storage-class keywords [extern], static, globaldef, and
globaldef{"name"}.
You can use both the readonly and noshare modifiers with the
[extern] and the globaldef{"name"} specifiers. If you use both
modifiers with either the static or the globaldef specifiers, the
compiler ignores noshare and accepts readonly.
14.3 – _align
The _align modifier allows you to align objects of any of the VSI C
data types on a specified storage boundary. Use the _align
modifier in a data declaration or definition.
When specifying the boundary of the data alignment, you can use a
predefined constant: BYTE or byte, WORD or word, LONGWORD or
longword, QUADWORD or quadword, OCTAWORD or octaword, and PAGE or
page.
You can also specify an integer value that is a power of two. The
power of two tells VSI C the number of bytes to pad in order to
align the data:
For OpenVMS VAX systems, specify a constant 0, 1, 2, 3, 4, or 9.
For OpenVMS Alpha systems, specify any constant from 0 to 16.
14.4 – __align
The __align storage-class modifier has the same semantic meaning as the _align keyword. The difference is that __align is a keyword in all compiler modes while _align is a keyword only in modes that recognize VAX C keywords. For new programs, using __align is recommended.
14.5 – __forceinline
Similar to the __inline storage-class modifier, the __forceinline
storage-class modifier marks a function for inline expansion.
However, using __forceinline on a function definition and prototype
tells the compiler that it must substitute the code within the
function definition for every call to that function. (With
__inline, such substitution occurs at the discretion of the
compiler.)
Syntax:
__forceinline [type] function_definition
14.6 – __inline
The __inline modifier marks a function for inline expansion. Using
__inline on a function definition and prototype tells the compiler
that it can substitute the code within the function definition for
every call to that function. Substitution occurs at the discretion
of the compiler. The __inline storage-class specifier has the same
effect as the #pragma inline preprocessor directive, except that
the latter attempts to provide inline expansion for all functions
in a translation unit, rather than for selected functions.
Syntax:
__inline [type] function_definition
14.7 – inline
Similar to the __inline storage-class modifier, the inline
storage-class modifier can be used as a declaration specifier in
the declaration of a function. This modifier is supported in
relaxed ANSI C mode (/STANDARD=RELAXED) or if the
/ACCEPT=C99_KEYWORDS or /ACCEPT=GCCINLINE qualifier is specified.
With static functions, inline has the same effect as applying
__inline or #pragma inline to the function.
However, when inline is applied to a function with external
linkage, besides allowing calls within that translation unit to be
inlined, the inline semantics provide additional rules that also
allow calls to the function to be inlined in other translation
units or for the function to be called as an external function, at
the compiler's discretion:
o If the inline keyword is used on a function declaration with
external linkage, then the function must also be defined in the
same translation unit.
o If all of the file scope declarations of the function use the
inline keyword but do not use the extern keyword, then the
definition in that translation unit is called an inline
definition, and no externally-callable definition is produced
by that compilation unit.
Otherwise, the compilation unit does produce an
externally-callable definition.
o An inline definition must not contain a definition of a
modifiable object with static storage duration, and it must not
refer to an identifier with internal linkage. These
restrictions do not apply to the externally-callable
definition.
o As usual, at most one compilation unit in an entire program can
supply an externally-callable definition of a given function.
o Any call to a function with external linkage may be translated
as a call to an external function, regardless of the presence
of the inline qualifier. It follows from this and the previous
point that any function with external linkage that is called
must have exactly one externally-callable definition among all
the compilation units of an entire program.
o The address of an inline function with external linkage is
always computed as the address of the unique
externally-callable definition, never the address of an inline
definition.
o A call to inline function made through a pointer to the
externally-callable definition may still be inlined or
translated as a call to an inline definition, if the compiler
can determine the name of the function whose address was stored
in the pointer.