United States

Compaq C

# Compaq C
User's Guide for OpenVMS Systems

Previous | Contents | Index

## 4.7.2 Bit-Field Initialization

The Compaq C compiler initializes bit fields in `struct` s differently than VAX C does. The following program compiles without error using both compilers but the results are different. Compaq C skips over unnamed bits but VAX C does not.

    #include <stdio.h>

    int t()
    {
       static struct bar {unsigned :1;
                   unsigned one : 1;
                   unsigned two : 1;
                  };
       struct bar foo = {1,0};
       printf("%d %d\n",foo.one,foo.two);
       return 1;
    }

When compiled with Compaq C, this example produces the following output:

    1 0

When compiled with VAX C, this example produces the following output:

    0 0

## 4.7.3 Variant Structures and Unions

Variant structures and unions are Compaq C extensions available in VAX C compatibility mode only, and they are not portable.

Variant structure and union declarations allow you to refer to members of nested aggregates without having to refer to intermediate structure or union identifiers. When a variant structure or union declaration is nested within another structure or union declaration, the enclosed variant aggregate ceases to exist as a separate aggregate, and Compaq C propagates its members to the enclosing aggregate.

Variant structures and unions are declared using the `variant_struct` and `variant_union` keywords. The format of these declarations is the same as that for regular structures or unions, with the following exceptions:

- Variant aggregates must be nested within other valid structure or union declarations.
- A tag cannot be used in a variant aggregate declaration.
- At least one declarator must be declared in the variant aggregate declaration, and it must not be declared as a pointer or an array.

Initialization of a variant structure or union is the same as that for a normal structure or union.

As with regular structures and unions, in VAX C compatibility mode, variant structures and unions in an assignment operation need only have the same size in bits, rather than requiring the same members and member types.

To show the use of variant aggregates, consider the following code example that does not use variant aggregates:

    /*  The numbers to the right of the code represent the byte offset  *
     *  from the enclosing structure or union declaration.              */
    struct  TAG_1
    {
       int   a;           /* 0-byte  enclosing_struct offset */
       char  *b;          /* 4-byte  enclosing_struct offset */
       union  TAG_2       /* 8-byte  enclosing_struct offset */
       {
          int  c;         /* 0-byte  nested_union offset */
          struct  TAG_3   /* 0-byte  nested_union offset */
          {
             int  d;      /* 0-byte  nested_struct offset */
             int  e;      /* 4-byte  nested_struct offset */
          }  nested_struct;
       } nested_union;
    } enclosing_struct;

If you want to access nested member `d` , then you need to specify all the intermediate aggregate identifiers:

    enclosing_struct.nested_union.nested_struct.d

If you try to access member `d` without specifying the intermediate identifiers, then you would access the incorrect offset from the incorrect structure. Consider the following example:

    enclosing_struct.d

The compiler uses the address of the original structure ( `enclosing_struct` ), and adds to it the assigned offset value for member `d` (0 bytes), even though the offset value for `d` was calculated according to the nested structure ( `nested_struct` ). Consequently, the compiler accesses member `a` (0-byte offset from `enclosing_struct` ) instead of member `d` .

The following code example shows the same code using variant aggregates:

    /*  The numbers to the right of the code present the byte offset  *
     *  from enclosing_struct.                                        */
    struct  TAG_1
    {
       int   a;           /* 0-byte  enclosing_struct offset */
       char  *b;          /* 4-byte  enclosing_struct offset */
       variant_union
       {
          int  c;         /* 8-byte  enclosing_struct offset */
          variant_struct
          {
             int  d;      /* 8-byte   enclosing_struct offset */
             int  e;      /* 12-byte  enclosing_struct offset */
          }  nested_struct;
       } nested_union;
    } enclosing_struct;

The members of the `nested_union` and `nested_struct` variant aggregates are propagated to the immediately enclosing aggregate ( `enclosing_struct` ). The variant aggregates cease to exist as individual aggregates.

Since the `nested_union` and `nested_struct` variant aggregates do not exist as individual aggregates, you cannot use tags in their declarations, and you cannot use their identifiers ( `nested_union` , `nested_struct` ) in any reference to their members. However, you are free to use the identifiers in other declarations and definitions within your program.

To access member `d` , use the following notation:

    enclosing_struct.d

Using the following notation causes unpredictable results:

    enclosing_struct.nested_union.nested_struct.d

If you use normal structure or union declarations within a variant aggregate declaration, the compiler propagates the structure or union to the enclosing aggregate, but the members remain a part of the nested aggregate. For example, if the nested structure in the last example was of type `struct` , the following offsets would be in effect:

    struct  TAG_1
    {
       int   a;           /* 0-byte  enclosing_struct offset */
       char  *b;          /* 4-byte  enclosing_struct offset */
       variant_union
       {
          int  c;         /* 8-byte  enclosing_struct offset */
          struct  TAG_2   /* 8-byte  enclosing-struct offset */
          {
             int  d;      /* 0-byte   nested_struct offset */
             int  e;      /* 4-byte   nested_struct offset */
          }  nested_struct;
       } nested_union;
    } enclosing_struct;

In this case, to access member `d` , use the following notation:

    enclosing_struct.nested_union.nested_struct.d

# 4.8 Program Sections

The following sections describe program-section attributes and program sections created by Compaq C for OpenVMS Systems.

## 4.8.1 Attributes of Program Sections

As the Compaq C compiler creates an object module, it groups data into contiguous program sections, or psects. The grouping depends on the attributes of the data and on whether the psects contain executable code or read/write variables.

The compiler also writes into each object module information about the program sections contained in it. The linker uses this information when it binds object modules into an executable image. As the linker allocates virtual memory for the image, it groups together program sections that have similar attributes.

Table 4-4 lists the attributes that can be applied to program sections.

Table 4-4 Program-Section Attributes
Attribute | Meaning
--- | ---
PIC or NOPIC | The program section or the data these attributes refers to does not depend on any specific virtual memory location (PIC), or else the program section depends on one or more virtual memory locations (NOPIC). 1
CON or OVR | The program section is concatenated with other program sections with the same name (CON) or overlaid on the same memory locations (OVR).
REL or ABS | The data in the program section can be relocated within virtual memory (REL) or is not considered in the allocation of virtual memory (ABS).
GBL or LCL | The program section is part of one cluster, is referenced by the same program section name in different clusters (GBL), or is local to each cluster in which its name appears (LCL).
EXE or NOEXE | The program section contains executable code (EXE) or does not contain executable code (NOEXE).
WRT or NOWRT | The program section contains data that can be modified (WRT) or data that cannot be modified (NOWRT).
RD or NORD | These attributes are reserved for future use.
SHR or NOSHR | The program section can be shared in memory (SHR) or cannot be shared in memory (NOSHR).
USR or LIB | These attributes are reserved for future use.
VEC or NOVEC | The program section contains privileged change mode vectors (VEC) or does not contain those vectors (NOVEC).
COM or NOCOM | The program section is a conditionally defined psect associated with a conditionally defined symbol. This is the type of psect created when you declare an uninitialized definition with `extern_model relaxed_refdef` .

1Compaq C programs can be bound into PIC or NOPIC shareable images. NOPIC occurs if declarations such as the following are used: char *x = &y;. This statement relies on the address of variable y to determine the value of the pointer x.

## 4.8.2 Program Sections Created by Compaq C

If necessary, Compaq C creates the following program sections:

- $CODE (VAX ONLY)---Contains all executable code and constant data (including variables defined with the `readonly` modifier or `const` type qualifier).
- $CODE$ (ALPHA ONLY)---Contains all executable code.
- $READONLY$ (ALPHA ONLY)---Contains all constant data defined with the `readonly` modifier or `const` type qualifier.
- $DATA (VAX ONLY) or $DATA$ (ALPHA ONLY)---Contains all static variables, as well as global variables defined without the `readonly` modifier or `const` type qualifier. $DATA also contains character-string constants when /ASSUME=WRITABLE_STRING_LITERALS is specified.
- $LITERAL$ (ALPHA ONLY)---Contains character-string constants when /ASSUME=NOWRITABLE_STRING_LITERALS is specified.
- Compaq C also creates additional program sections for variables declared with the `globaldef` keyword if the optional psect name in braces is specified, or for variables declared with the `extern` storage class, depending on the external model.

All program sections created by Compaq C have the PIC, REL, RD, USR, and NOVEC attributes. On OpenVMS VAX systems, the $CODE psect is aligned on a byte boundary; all other psects generated by Compaq C are aligned on longword boundaries. On OpenVMS Alpha systems, all psects generated by Compaq C are aligned on octaword boundaries. Note that use of the `_align` storage-class modifier can cause a psect to be aligned on greater than a longword boundary on OpenVMS VAX systems. The $CHAR_STRING_CONSTANTS psect has the same attributes as the $DATA (VAX ONLY) and $DATA$ (ALPHA ONLY) psects.

Tables 4_5 , 4_6 , 4_7 , and 4-8 summarize the differences in psects created by different declarations:

- Table 4_5 , Table 4_6 (ALPHA ONLY) , and Table 4-7 (VAX ONLY) show different cases of variable definitions and assign to them a storage-class code number:
  - Table 4-5 shows the effect of each `#pragma extern_model` preprocessor directive on the storage-class code number for external variable definitions that have an `extern` storage class.
  - Table 4-6 shows the storage-class code number for variable definitions that do not have the `extern` storage class on OpenVMS Alpha systems.
  - Table 4-7 shows the storage-class code number for variable definitions that do not have the `extern` storage class on OpenVMS VAX systems.
- Table 4-8 shows the psect name and attributes associated with each storage-class code number from Tables 4-5, 4_6, and 4-7.

Table 4-5 External Models and Definitions
Storage- Class Code | External Object Definition | Interpretation
--- | --- | ---
External Model: `pragma extern_model common_block noshr`
1 | `int name;` | /* uninitialized definition */
1 | `int name = 1;` | /* initialized definition */
1 | `extern int name;` | /* treated as an uninitialized definition */
2 | `const int name;` | /* uninitialized definition */
2 | `const int name = 1;` | /* initialized definition */
2 | `extern const int name;` | /* treated as an uninitialized definition */
External Model: `pragma extern_model common_block shr`
3 | `int name;` | /* uninitialized definition */
3 | `int name = 1;` | /* initialized definition */
3 | `extern int name;` | /* treated as an uninitialized definition */
4 | `const int name;` | /* uninitialized definition */
4 | `const int name = 1;` | /* initialized definition */
4 | `extern const int name;` | /* treated as an uninitialized definition */
External Model: `pragma extern_model relaxed_refdef noshr`
5 | `int name;` | /* uninitialized definition */
1 | `int name = 1;` | /* initialized definition */
6 | `const int name;` | /* uninitialized definition */
2 | `const int name = 1;` | /* initialized definition */
External Model: `pragma extern_model relaxed_refdef shr`
7 | `int name;` | /* uninitialized definition */
3 | `int name = 1;` | /* initialized definition */
8 | `const int name;` | /* uninitialized definition */
4 | `const int name = 1;` | /* initialized definition */
External Model: `pragma extern_model strict_refdef`
9 (ALPHA ONLY) | `int symbol;` | /* uninitialized definition */
10 (VAX ONLY) | `int symbol;` | /* uninitialized definition */
10 | `int symbol = 1;` | /* initialized definition */
11 | `const int symbol;` | /* uninitialized definition */
11 | `const int symbol = 1;` | /* initialized definition */
External Model: `pragma extern_model strict_refdef "name" noshr`
12 | `int symbol;` | /* uninitialized definition */
12 | `int symbol = 1;` | /* initialized definition */
13 | `const int symbol;` | /* uninitialized definition */
13 | `const int symbol = 1;` | /* initialized definition */
External Model: `pragma extern_model strict_refdef "name" shr`
14 | `int symbol;` | /* uninitialized definition */
14 | `int symbol = 1;` | /* initialized definition */
15 | `const int symbol;` | /* uninitialized definition */
15 | `const int symbol = 1;` | /* initialized definition */

Table 4-6 Combinations of Storage-Class Specifiers and Modifiers (ALPHA ONLY)
Storage- Class Code | Storage-Class Keyword Combination | /SHARE or /NOSHARE | Initialized or Not
--- | --- | --- | ---
9 | `static` | Either | No
10 | `static` | Either | Yes
11 | `static const` 1 | Either | Either
9 | `globaldef` | Either | No
10 | `globaldef` | Either | Yes
11 | `globaldef const` 1 | Either | Either
14 | `globaldef` {"name"} | /SHARE | Either
12 | `globaldef` {"name"} | /NOSHARE | Either
15 | `globaldef` {"name"} `const` 1 | /SHARE | Either
13 | `globaldef` {"name"} `const` 1 | /NOSHARE | Either

1Using `readonly` in place of `const` produces the same results.

Table 4-7 Combinations of Storage-Class Specifiers and Modifiers (VAX ONLY)
Storage- Class Code | Storage-Class Keyword Combination | /SHARE or /NOSHARE
--- | --- | ---
10 | `static` | Either
11 | `static const` 1 | Either
10 | `globaldef` | Either
11 | `globaldef const` 1 | Either
14 | `globaldef` {"name"} | /SHARE
12 | `globaldef` {"name"} | /NOSHARE
15 | `globaldef` {"name"} `const` 1 | /SHARE
13 | `globaldef` {"name"} `const` 1 | /NOSHARE

1Using `readonly` in place of `const` produces the same results.

Table 4-8 shows the psect name and psect attributes for the storage-class code numbers from Table 4_5, Table 4-6, and Table 4-7. Where `name` is used for the psect name in Table 4-8, the name of the psect is the same as `name` in the declarations or pragmas in Table 4-5, or the quoted brace-enclosed names in Tables 4_6 and 4-7.

Table 4-8 Combination Attributes
Storage- Class Code | Program Section Name | Program Attributes
--- | --- | ---
1 | `name` | OVR, GBL, NOSHR, NOEXE, WRT, NOCOM
2 | `name` | OVR, GBL, NOSHR, NOEXE, NOWRT, NOCOM
3 | `name` | OVR, GBL, SHR, NOEXE, WRT, NOCOM
4 | `name` | OVR, GBL, SHR, NOEXE, NOWRT, NOCOM
5 | `name` | OVR, GBL, NOSHR, NOEXE, WRT, COM
6 | `name` | OVR, GBL, NOSHR, NOEXE, NOWRT, COM
7 | `name` | OVR, GBL, SHR, NOEXE, WRT, COM
8 | `name` | OVR, GBL, SHR, NOEXE, NOWRT, COM
9 | $BSS$ | CON, LCL, NOSHR, NOEXE, WRT, NOCOM
10 | $DATA (VAX ONLY) | CON, LCL, NOSHR, NOEXE, WRT, NOCOM
10 | $DATA$ (ALPHA ONLY) | CON, LCL, NOSHR, NOEXE, WRT, NOCOM
11 | $CODE (VAX ONLY) | CON, LCL, SHR, EXE, NOWRT, NOCOM
11 | $READONLY$ (ALPHA ONLY) | CON, LCL, SHR, NOEXE, NOWRT, NOCOM
12 | "name" | CON, GBL, NOSHR, NOEXE, WRT, NOCOM
13 | "name" | CON, GBL, NOSHR, NOEXE, NOWRT, NOCOM
14 | "name" | CON, GBL, SHR, NOEXE, WRT, NOCOM
15 | "name" | CON, GBL, SHR, NOEXE, NOWRT, NOCOM

Previous | Next | Contents | Index

privacy and legal statement