United States

Compaq C

# Compaq C
User's Guide for OpenVMS Systems

Previous | Contents | Index

# Chapter 4
Data Storage and Representation

This chapter presents the following topics concerning Compaq C data storage and representation on OpenVMS systems:

- Storage allocation ( Section 4.1)
- ANSI-compliant method of controlling external objects ( Section 4.2)
- Global storage classes ( Section 4.3)
- Storage-class modifiers ( Section 4.4)
- Floating-point numbers ( Section 4.5)
- Pointer conversions ( Section 4.6)
- Structure alignment ( Section 4.7)
- Program sections ( Section 4.8)

# 4.1 Storage Allocation

When you define a Compaq C variable, the storage class determines not only its scope but also its location and lifetime. The lifetime of a variable is the length of time for which storage is allocated. For OpenVMS systems, storage for a Compaq C variable can be allocated in the following locations:

- On the run-time stack
- In a machine register
- In a program section (psect)

Variables that are placed on the stack or in a register are temporary. For example, variables of the `auto` and `register` storage classes are temporary. Their lifetimes are limited to the execution of a single block or function. All declarations of the internal storage classes ( `auto` and `register` ) are also definitions; the compiler generates code to establish storage at this point in the program.

Program sections, or psects, are used for permanent variables; the lifetime of identifiers extends through the course of the entire program. A psect represents an area of virtual memory that has a name, a size, and a series of attributes that describe the intended or permitted usage of that portion of memory. For example, the compiler places variables of the static, external, and global storage classes in psects; you have some control as to which psects contain which identifiers. All declarations of the static storage class are also definitions; the compiler creates the psect at that point in the program. In Compaq C, the first declaration of the external storage class is also a definition; the linker initializes the psect at that point in the program.

Note The compiler does not necessarily allocate distinct variables to memory locations according to the order of appearance in the source code. Furthermore, the order of allocation can change as a result of seemingly unrelated changes to the source code, command-line options, or from one version of the compiler to the next; it is essentially unpredictable. The only way to control the placement of variables relative to each other is to make them members of the same `struct` type or, on OpenVMS Alpha systems, by using the `noreorder` attribute on a named `#pragma extern_model strict_refdef` .

Table 4-1 shows the location and lifetime of a variable when you use each of the storage-class keywords.

Table 4-1 Location, Lifetime, and the Storage-Class Keywords
Storage Class | Location | Lifetime
--- | --- | ---
(Internal null) | Stack or register | Temporary
`[auto]` | Stack or register | Temporary
`register` | Stack or register | Temporary
`static` | Psect | Permanent
`extern` | Psect | Permanent
`globaldef` 1 | Psect | Permanent
`globalref` 1 | Psect | Permanent
`globalvalue` 1 | No storage allocated | Permanent

1The `globaldef`, `globalref`, and `globalvalue` storage-class specifiers are available only when compiling in VAX C compatibility mode.

For a comparison between the global and external storage classes, see Section 4.3.2.

For more information about psects, see Section 4.8.

# 4.2 ANSI-Compliant Method of Controlling External Objects

Sections 4.3 and 4.4 describe the following external linkage storage-class specifiers and modifiers that are specific to Compaq C for OpenVMS Systems:

> `globaldef`
> `globalref`
> `globalvalue`
> `noshare`
> `readonly`
> `_align`

These keywords are supported by the Compaq C compiler for compatibility purposes, and are available only in VAX C mode (/STANDARD=VAXC) and relaxed ANSI C mode (/STANDARD=RELAXED_ANSI89).

However, the Compaq C compiler also provides an alternative, ANSI-compliant method of controlling objects that have external linkage. To take advantage of this method, use the `#pragma extern_model` preprocessor directive and the /EXTERN_MODEL and /[NO]SHARE_GLOBALS command-line qualifiers.

The pragma and command-line qualifiers replace the VAX C mode storage-class specifiers ( `globaldef` , `globalref` , `globalvalue` ) and storage-class modifiers ( `noshare` and `readonly` ). They allow you to select the implementation model of external data and control the psect usage of your programs. The `_align` macro is still used to ensure object alignment.

The pragma and command-line qualifier approach also has these advantages:

- Since the VAX C mode keywords do not follow ANSI C spelling rules, they cannot be provided in strict ANSI C mode. The pragma and qualifiers, however, can be used in any mode of the Compaq C compiler.
- The pragma and qualifiers allow `extern` on OpenVMS systems to function in a manner more similar to other systems.
- The pragma and qualifiers make it easier for you to write OpenVMS shareable images with Compaq C. Previously, that task required you to add an additional keyword to every declaration of external data.

For a description of the `#pragma extern_model` preprocessor directive and its relationship to the external storage classes it replaces, see Section 5.4.5.

For a description of the `_align` storage-class modifier, see Section 4.4.3.

For a description of the /EXTERN_MODEL and /[NO]SHARE_GLOBALS command-line qualifiers, see Section 1.3.4.

# 4.3 Global Storage Classes

In addition to the storage-class specifiers described in the Compaq C Language Reference Manual, the VAX C compatibility mode of Compaq C provides the `globaldef` , `globalref` , and `globalvalue` storage-class specifiers. These specifiers allow you to assign the global storage classes to identifiers. The global storage classes are specific to Compaq C for OpenVMS Systems and are not portable.

## 4.3.1 The globaldef and globalref Specifiers

Use the `globaldef` specifier to define a global variable. Use the `globalref` specifier to refer to a global variable defined elsewhere in the program.

When you use the `globaldef` specifier to define a global symbol, the symbol is placed in one of three program sections: the $DATA (VAX ONLY) or $DATA$ (ALPHA ONLY) psect using `globaldef` alone, the $CODE (VAX ONLY) or $READONLY$ (ALPHA ONLY) psect using `globaldef` with `readonly` or `const` , or a user-named psect. You can create a user-named psect by specifying the psect name as a string constant in braces immediately following the `globaldef` keyword, as shown in the following definition:

    globaldef{"psect_name"}  int x = 2;

This definition creates a program section called `psect_name` and allocates the variable `x` in that psect. You can add any number of global variables to this psect by specifying the same psect name in other `globaldef` declarations. In addition, you can specify the `noshare` modifier to create the psect with the NOSHR attribute. Similarly, you can specify the `readonly` or `const` modifier to create the psect with the NOWRT attribute. 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.

Variables declared with `globaldef` can be initialized; variables declared with `globalref` cannot, because these declarations refer to variables defined, and possibly initialized, elsewhere in the program. Initialization is possible only when storage is allocated for an object. This distinction is especially important when the `readonly` or `const` modifier is used; unless the global variable is initialized when the variable is defined, its permanent value is 0.

Note In the VAX MACRO programming language, it is possible to give a global variable more than one name. However, in Compaq C, only one global name can be used for a particular variable. Compaq C assumes that distinct global variable names denote distinct objects; the storage associated with different names must not overlap.

Example 4-1 shows the use of global variables.

Example 4-1 Using Global Variables

    /*  This example shows how global variables are used      *
     *  in Compaq C programs.                                 */

    #include <stdlib.h>

    (1)int ex_counter = 0;
    (2)globaldef double velocity = 3.0e10;
    (3)globaldef {"distance"} long miles = 100;

    int main()
    {
       printf("   *** FIRST COMP UNIT ***\n");
       printf("counter:\t%d\n", ex_counter);
       printf("velocity:\t%g\n", velocity);
       printf("miles:\t\t%d\n\n", miles);
       fn();
       printf("   *** FIRST COMP UNIT ***\n");
       printf("counter:\t%d\n", ex_counter);

    (4)   printf("velocity:\t%g\n", velocity);
       printf("miles:\t\t%d\n\n", miles);
    exit (EXIT_SUCCESS);
    }

    /*  ----------------------------------------------------  *
     *  The following code is contained in a separate         *
     *  compilation unit.                                     *
     *  ----------------------------------------------------  */

    static ex_counter;
    (5)globalref double velocity;
    globalref long miles;

    fn(void)
    {
       ++ex_counter;
       printf("   *** SECOND COMP UNIT ***\n");
       if ( miles > 50 )
          velocity = miles * 3.1 / 200 ;
       printf("counter:\t%d\n", ex_counter);
       printf("velocity:\t%g\n", velocity);
       printf("miles:\t\t%d\n", miles);
    }

Key to Example 4-1:

1. In the first compilation unit, the `ex_counter` integer variable has a storage class of `extern` . In the second compilation unit, a variable named `ex_counter` is of storage class `static` . Even though they have the same identifier, the two `ex_counter` variables are different variables represented by two separate memory locations. The link-time scope of the second `ex_counter` is the module created from the second compilation unit. When control returns to the main function, the `ex_counter` external variable retains its original value.
2. The variable `velocity` has storage class `globaldef` and is stored in the $DATA psect (VAX ONLY) or $DATA$ psect (ALPHA ONLY).
3. The `miles` variable also has storage class `globaldef` but is stored in the user-specified psect `"distance"` .
4. When the `velocity` variable prints after the function `fn` executes, the value will have changed. Global variables have only one storage location.
5. When you reference global variables in another module, you must declare those variables in that module. In the second module, the global variables are declared with the `globalref` keyword.

Sample output from Example 4-1 is as follows:

    $ RUN EXAMPLE.EXE[Return]
       *** FIRST COMP UNIT ***
    counter:        0
    velocity:       3.000000e+10
    miles:          100
       *** SECOND COMP UNIT ***
    counter:        1
    velocity:       1.55
    miles:          100
       *** FIRST COMP UNIT ***
    counter:        0
    velocity:       1.55
    miles:          100

## 4.3.2 Comparing the Global and the External Storage Classes

The global storage-class specifiers define and declare objects that differ from external variables both in their storage allocation and in their correspondence to elements of other languages. Global variables provide a convenient and efficient way for a Compaq C function to communicate with assembly language programs, with OpenVMS system services and data structures, and with other high-level languages that support global symbol definition, such as Compaq PL/I. For more information about multilanguage programming, see Chapter 3.

Compaq C imposes no limit on the number of external variables in a single program.

There are other functional differences between the external and global variables. For example:

- If you have a limited amount of storage available, you may use the `globalvalue` specifier (see Section 4.3.3) since an object defined as a `globalvalue` does not occupy storage in your program; the external variables create program sections.
- You can declare a global variable, using `globaldef` , inside a function or block, and by using a `globalref` specifier, access the identifier from another compilation unit. With external variables, you must define the variable outside all functions and blocks, and then access that variable in other compilation units by using `extern` declarations.
- The global variables correspond to global symbols declared in assembly language programs, but external variables ( `extern` ) correspond with FORTRAN common blocks.
- A `globalref` declaration causes the linker to load the module containing the corresponding `globaldef` into the image (unless the `globalref` is not referenced, in which case Compaq C optimizes it away). An `extern` declaration does not cause the linker to do so. An `extern` declaration causes an overlaying of a psect (see Section 4.8 for details about psects).
  In programming environments other than the OpenVMS environment, C programmers may be accustomed to `extern` declarations causing the loading of a module into the program's executable image. If transportability is an issue, you can define the following symbols---at the compilation-unit level, outside of all functions---to allocate storage differently depending on the system you are using:

      #ifdef   __DECC
      #define  EXPORT  globaldef
      #define  IMPORT  globalref
      #else
      #define  EXPORT
      #define  IMPORT  extern
      #endif
         .
         .
         .
      IMPORT int foo;
      EXPORT int foo = 53;

One similarity between the external and global storage classes is in the way the compiler recognizes these variables internally. External and global identifiers are not case-sensitive. No matter how the external and global identifiers appear in the source code, the compiler converts them to uppercase letters (unless you compile with /NAMES=AS_IS or /NAMES=LOWERCASE). For ease in debugging programs, express all global and external variable identifiers in uppercase letters.

Another similarity between the external and global storage classes is that you can place the external variables and the global variables (optionally) in psects with a user-defined name and, to some degree, user-defined attributes. The compiler places external variables in psects of the same name as the variable identifier, viewed by the linker in uppercase letters. The compiler places `globaldef` {"name"} variables in psects with names specified in quotation marks, delimited by braces, and located directly after the `globaldef` specifier in a declaration. Again, the linker considers the psect name to be in uppercase letters.

The compiler places a variable declared using only the `globaldef` specifier and a data-type keyword into the $DATA (VAX ONLY) or $DATA$ (ALPHA ONLY) psect. 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.

## 4.3.3 The globalvalue Specifier

A global value is an integral value whose identifier is a global symbol. Global values are useful because they allow many programmers in the same environment to refer to values by identifier, without regard to the actual value associated with the identifier. The actual values can change, as dictated by general system requirements, without requiring changes in all the programs that refer to them. If you make changes to the global value, you only have to recompile the defining compilation unit (unless it is defined in an object library), not all of the compilation units in the program that refer to those definitions.

Note You can use the `globalvalue` specifier only with identifiers of type `enum` , `int` , or with pointer variables.

An identifier declared with `globalvalue` does not require storage. Instead, the linker resolves all references to the value. If an initializer appears with `globalvalue` , the name defines a global symbol for the given initial value. If no initializer appears, the `globalvalue` construct is considered a reference to some previously defined global value.

Predefined global values serve many purposes in OpenVMS system programming, such as defining status values. It is customary in OpenVMS system programming to avoid explicit references to such values as those returned by system services, and to use instead the global names for those values. Example 4-2 shows the use of the `globalvalue` storage-class specifier.

Example 4-2 Using the globalvalue Specifier

    /*  This program shows references to previously defined        *
     *  globalvalue symbols.                                       */

    #include <stdio.h>
    globalvalue FAILURE = 0, EOF = -1;

    main()
    {
       char c;
                                       /* Get a char from stdin    */
       while ( (c = getchar())  !=  EOF)
          test(c);
    }

    /*  --------------------------------------------------------   *
     *  The following code is contained in a separate compilation  *
     *  unit.                                                      *
     *  --------------------------------------------------------   */

    #include <ctype.h>                 /* Include proper module    */
    globalvalue  FAILURE,  EOF;        /* Declare global symbols   */

    void test(param_c)
    char param_c;                      /* Declare parameter        */
    {
                                       /* Test to see if number is valid */
       if ( (isalnum(param_c))  !=  FAILURE)
          printf("%c\n", param_c);
       return;
    }

In Example 4-2, `FAILURE` and `EOF` are defined in the first module: the values are placed into the program stream. In the second module, `FAILURE` and `EOF` are declared so that their values can be accessed. As with the external and global variables, the linker converts the global symbols as uppercase letters. For ease of debugging, express these symbols in uppercase.

Previous | Next | Contents | Index

privacy and legal statement