United States

Compaq C

# Compaq C
User's Guide for OpenVMS Systems

Previous | Contents | Index

# 4.4 Storage-Class Modifiers

Compaq C for OpenVMS Systems provides support for the storage-class modifiers `noshare` , `readonly` , and `_align` as VAX C keywords. The recognition of these three storage-class modifiers as keywords (along with the other VAX C specific keywords) is controlled by a combination of the compiler mode and the /ACCEPT command-line qualifier. The default behavior on OpenVMS systems is for the compiler to recognize these storage-class modifiers as keywords in the VAX C compatibility mode and relaxed ANSI C mode (assuming that /ACCEPT=NOVAX_KEYWORDS is not also specified.) Conversely, they are not recognized by default in all other modes unless overridden by /ACCEPT=VAX_KEYWORDS.

Compaq C also provides the `__inline` , `__forceinline` and `__align` storage-class modifiers. These are recognized as valid keywords in all compiler modes on all platforms. They are in the namespace reserved to the C implementation, so it is not necessary to allow them to be treated as user-declared identifiers. They have the same effects on all platforms, except that on OpenVMS VAX systems, the `__forceinline` modifier does not cause any more inlining than the `__inline` modifier does.

Compaq C also provides the `inline` storage-class modifier. This modifier is supported in relaxed ANSI C mode (/STANDARD=RELAXED_ANSI89) or if the /ACCEPT=C99_KEYWORDS or /ACCEPT=GCCINLINE qualifier is specified.

For additional detail about the `__inline` , `__forceinline` , `__align` , and `inline` storage-class modifiers, see the Compaq C Language Reference Manual.

You can use a storage-class specifier and a storage-class modifier in any order; usually, the modifier is placed after the specifier in the source code. For example:

    extern  noshare  int  x;

       /*  Or, equivalently...*/

    int  noshare  extern  x;

The following sections describe each of the Compaq C storage-class modifiers.

## 4.4.1 The noshare Modifier

The `noshare` storage-class modifier assigns the attribute NOSHR to the program section of the variable. Use this modifier to allow other programs, used as shareable images, to have a copy of the variable's psect without the shareable images changing the variable's value in the original psect.

When a variable is declared with the `noshare` modifier and a shared image that has been linked to your program refers to that variable, a copy is made of the variable's original psect to a new psect in the other image. The other program may alter the value of that variable within the local psect without changing the value still stored in the psect of the original program.

For example, if you need to establish a set of data that will be used by several programs to initialize local data sets, then declare the external variables using the `noshare` specifier in a Compaq C program. Each program receives a copy of the original data set to manipulate, but the original data set remains for the next program to use. If you define the data as `extern` without the `noshare` modifier, a copy of the psect of that variable is not made; each program would be allowed access to the original data set, and the initial values would be lost as each program stores the values for the data in the psect. If the data is declared as `const` or `readonly` , each program is able to access the original data set, but none of the programs can then change the values.

You can use the `noshare` modifier with the `static` , `extern` , `globaldef` , and `globaldef` {"name"} storage-class specifiers. For more information about the possible combinations of specifiers and modifiers, and the effects of the storage-class modifiers on program-section attributes, see Section 4.8.

You can use `noshare` alone, which implies an external definition of storage class `extern` . Also, when declaring variables using the `extern` and `globaldef` {"name"} storage-class specifiers, you can use `noshare` , `const` , and `readonly` , together, in the declaration. If you declare variables using the `static` or the `globaldef` specifiers, and you use both of the modifiers in the declaration, the compiler ignores `noshare` and accepts `const` or `readonly` .

## 4.4.2 The readonly Modifier

The `readonly` storage-class modifier, like the `const` data-type qualifier, assigns the NOWRT attribute to the variable's program section; if used with the `static` or `globaldef` specifier, the variable is stored in the $CODE psect, which has the NOWRT attribute by default.

You can use both the `readonly` and `const` modifiers with the `static` , `extern` , `globaldef` , and `globaldef` {"psect"} storage-class specifiers.

In addition, both the `readonly` modifier and the `const` modifier can be used alone. When you specify these modifiers alone, an external definition of storage class `extern` is implied.

The `const` modifier restricts access to data in the same manner as the `readonly` modifier. However, in the declaration of a pointer, the `readonly` modifier cannot appear between the asterisk and the pointer variable to which it applies.

The following example shows the similarity between the `const` and `readonly` modifiers. In both instances, the `point` variable represents a constant pointer to a nonconstant integer.

    readonly int * point;

    int * const point;

Note For new program development, DIGITAL recommends that you use the `const` modifier, because `const` is ANSI C compliant and `readonly` is not.

## 4.4.3 The _align Modifier

The `_align` storage-class modifier aligns objects of any of the Compaq C data types on a specified storage boundary. Use the `_align` modifier in a data declaration or definition.

For example, to align an integer on the next quadword boundary, you can use any of the following declarations:

    int  _align( QUADWORD )  data;
    int  _align( quadword )  data;
    int  _align( 3 )  data;

When specifying the boundary of the data alignment, you can either use a predefined constant or specify an integer value that is a power of 2. These constants, or explicit powers of 2, tell Compaq C the number of bytes to pad in order to align the data. In the previous example, `int _align ( 3 )` specifies an alignment of 23 bytes, which is 8 bytes---a quadword of memory.

Table 4-2 presents all the predefined alignment constants, their equivalent power of 2, and their equivalent number of bytes. Note that for OpenVMS VAX systems, you can specify the constants 0, 1, 2, 3, 4, or 9. For OpenVMS Alpha systems, you can specify any constant from 0 to 16.

Table 4-2 Predefined Alignment Constants
Constant | Power of 2 | Number of Bytes
--- | --- | ---
BYTE or byte | 0 | 1
WORD or word | 1 | 2
LONGWORD or longword | 2 | 4
QUADWORD or quadword | 3 | 8
OCTAWORD or octaword | 4 | 16
| 5 (ALPHA ONLY) | 32
| 6 (ALPHA ONLY) | 64
| 7 (ALPHA ONLY) | 128
| 8 (ALPHA ONLY) | 256
| 9 | 512
| 10 (ALPHA ONLY) | 1024
| 11 (ALPHA ONLY) | 2048
| 12 (ALPHA ONLY) | 4096
| 13 (ALPHA ONLY) | 8192
| 14 (ALPHA ONLY) | 16384
| 15 (ALPHA ONLY) | 32768
PAGE or page | 16 (ALPHA ONLY) 9 (VAX ONLY) | 65,536 (ALPHA ONLY) 512 (VAX ONLY)

# 4.5 Floating-Point Numbers (float, double, long double)

When declaring floating-point variables, you determine the amount of precision needed for the stored object. In Compaq C, you can have single-precision, double-precision, and extended double-precision variables.

The `float` keyword declares a single-precision, floating-point variable. A `float` variable is represented internally in the VAX compatible, F_floating-point binary format.

For double-precision variables, you can choose D_floating or G_floating. On Alpha systems, you can also choose single- and double-precision IEEE formats (S_floating and T_floating, respectively), and extended double-precision format (X_floating).

The `double` keyword declares a double-precision, floating-point variable. Compaq C provides two VAX C compatible formats for specifying `double` variables: D_floating or G_floating.

The G_floating precision of approximately 15 digits is less than that of variables represented in D_floating format. Although there are more bits allocated to the exponent in G_floating precision, fewer bits are allocated to the mantissa, which determines precision (see Table 4-3 ).

Note When the compiler is run with the /STANDARD=VAXC qualifier, the use of the `long float` keyword, which is interchangeable with the `double` keyword, is allowed but elicits a warning that this is obsolete usage. The `long float` keyword is not allowed when the compiler is run with the /STANDARD=ANSI89 qualifier.

In VAX C, the default representation of `double` variables is D_floating. To select the G_floating representation, you compiled with the /G_FLOAT qualifier.

In Compaq C, the /FLOAT qualifier replaces the /G_FLOAT qualifier, but /G_FLOAT is retained for compatibility.

When compiling with Compaq C on OpenVMS VAX systems, if you omit both /G_FLOAT and /FLOAT, the default representation of `double` variables is D_floating (unless /MIA is specified, in which case the default is G_floating).

When compiling with Compaq C on OpenVMS Alpha systems, if you omit both /G_FLOAT and /FLOAT, the default representation of `double` variables is G_floating.

For OpenVMS Alpha systems, the /FLOAT qualifier accepts the additional option IEEE_FLOAT. If you specify /FLOAT=IEEE_FLOAT, single and `double` variables are represented in IEEE_floating format (S_floating for single float, and T_floating for `double` float).

You cannot specify both the /FLOAT and /G_FLOAT qualifiers on the command line.

Note The VAX D_floating double-precision floating-point type is minimally supported on OpenVMS Alpha systems. When compiling with this type, all data transfer is done with the data in D_floating format, but for each arithmetic operation the data is converted first to G_floating and then back to D_floating format when the operation is complete. Therefore, it is possible to lose three binary digits of precision in arithmetic operations. This floating-point type is provided for compatibility with OpenVMS VAX systems.

Modules compiled with the D_floating representation should not be linked with modules compiled with the G_floating representation. Since there are no functions in the Compaq C Run-Time Library (RTL) that perform floating-point format conversions on files, use the OpenVMS RTL functions MTH$CVT_D_G, MTH$CVT_G_D, MTH$CVT_DA_GA, and MTH$CVT_GA_DA if you do not wish to recompile the program. For more information about using the OpenVMS RTL, see the VMS Run-Time Library Routines Volume.

On OpenVMS VAX systems, Compaq C maps the ANSI C defined `long double` type to the G_floating or D_floating format.

On OpenVMS Alpha systems, `long double` variables are represented by default in the software-emulated X_floating format. If you specify /L_DOUBLE_SIZE=64, `long double` variables are represented as G_floating, D_floating, or T_floating, depending on the value of the /FLOAT or /G_FLOAT qualifier.

Note Modules must be linked to the appropriate run-time library. For more information about linking against the Compaq C RTL shareable image and object libraries, see the Compaq C Run-Time Library Reference Manual for OpenVMS Systems.

Table 4-3 shows the supported floating-point formats, and their approximate sizes and range of values.

Table 4-3 Floating-Point Formats
Data type | Floating-Point Format | Length of Variable | Range of Values | Precision (decimal digits)
--- | --- | --- | --- | ---
`float` | F_floating | 32-bit | 2.9 * 10 -39 to 1.7 * 10 38 | 6
`double` | D_floating | 64-bit | 2.9 * 10 -39 to 1.7 * 10 38 | 16
`double` | G_floating | 64-bit | 5.6 * 10 -309 to 9.0 * 10 307 | 15
`float` | S_floating (ALPHA ONLY) | 32-bit | 1.2 * 10 -38 to 3.4 * 10 38 | 6
`double` | T_floating (ALPHA ONLY) | 64-bit | 2.2 * 10 -308 to 1.8 * 10 308 | 15
`long double` | X_floating (ALPHA ONLY) | 128-bit | 3.4 * 10 -4932 to 1.2 * 10 4932 | 33

# 4.6 Pointer Conversions

When running the compiler in VAX C mode, relaxed pointer and pointer/integer compatibility is allowed. That is, all pointer and integer types are compatible, and pointer types are compatible with each other regardless of the type of the object they point to. Therefore, in VAX C mode, a pointer to `float` is compatible with a pointer to `int` . This is not true in ANSI C mode.

Although pointer conversions do not involve a representation change when compiling in VAX C mode, because of alignment restrictions on some machines, access through an unaligned pointer can result in much slower access time, a machine exception, or unpredictable results.

# 4.7 Structure Alignment

The alignment and size of a structure is affected by the alignment requirements and sizes of the structure components for each Compaq C platform. A structure can begin on any byte boundary and occupy any integral number of bytes. However, individual architectures or operating systems can specify particular alignment and padding requirements.

Compaq C on VAX processors does not require that structures or structure members be aligned on any particular boundaries.

The components of a structure are laid out in memory in the order they are declared. The first component has the same address as the entire structure. On VAX processors, each additional component follows its predecessor in the immediately following byte.

For example, the following type is aligned as shown in Figure 4-1:

    struct {char c1;
            short s1;
            float f;
            char c2;
            }

Figure 4-1 OpenVMS VAX Structure Alignment

The alignment of the entire structure can occur on any byte boundary, and no padding is introduced. The `float` variable `f` may span longwords, and the `short` variable `s1` may span words.

The following pragma can be used to force specific alignments:

    #pragma member_alignment

Structure alignment for Compaq C for OpenVMS Systems on VAX processors is achieved by the default, `#pragma nomember_alignment` , which causes data structure members to be byte-aligned (with the exception of bit-field members).

Structure alignment for Compaq C for OpenVMS Systems on Alpha processors is achieved by the default, `#pragma member_alignment` , which causes data structure members to be naturally aligned. This means that data structure members are aligned on the next boundary appropriate to the type of the member, rather than on the next byte.

For more information on the `#pragma member_alignment` preprocessor directive, see Section 5.4.11.

## 4.7.1 Bit-Field Alignment

Bit fields can have any integral type. However, the compiler issues a warning if /STANDARD=ANSI89 is specified, and the type is something other than `int` , `unsigned int` , or `signed int` . Bit fields are allocated within the unit from low order to high order. If a bit field immediately follows another bit field, the bits are packed into adjacent space, even if this overflows into another byte. However, if an unnamed bit field is specified to have length 0, filler is added so the bit field immediately following starts on the next byte boundary.

For example, the following type is aligned as shown in Figure 4-2:

            struct {int i:2;
                    int ii:2;
                    unsigned int ui: 30;
                    }

Figure 4-2 OpenVMS Bit-Field Alignment

Bit field `ii` is positioned immediately following bit field `i` . Because there are only 28 bit positions remaining and `ui` requires 30 bits, the first 28 bits of `ui` are put into the first longword, and the remaining two bits overflow into the next longword.

Previous | Next | Contents | Index

privacy and legal statement