[an error occurred while processing this directive]

HP OpenVMS Systems

C Programming Language
Content starts here HP C

HP C
User's Guide for OpenVMS Systems


Previous Contents Index

4.3 Global Storage Classes

In addition to the storage-class specifiers described in the HP C Language Reference Manual, the VAX C compatibility mode of HP 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 HP 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, I64) psect using globaldef alone, the $CODE (VAX ONLY) or $READONLY$ (ALPHA, I64) 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 HP C, only one global name can be used for a particular variable. HP 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 HP C programs.                                     */ 
 
#include <stdlib.h> 
 
#include <stdio.h> 
extern void fn(); 
 
 
(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.                                     * 
 *  ----------------------------------------------------  */ 
 
 
#include <stdio.h> 
 
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, I64).
  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 HP 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 HP PL/I. For more information about multilanguage programming, see Chapter 3.

HP 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 HP 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. 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, I64) 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.

4.4 Storage-Class Modifiers

HP 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 mode (assuming that /ACCEPT=NOVAXC_KEYWORDS is not also specified.) Conversely, they are not recognized by default in all other modes unless overridden by /ACCEPT=VAXC_KEYWORDS.

HP 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 VAX systems, the __forceinline modifier does not cause any more inlining than the __inline modifier does.

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

For additional information about the __inline , __forceinline , __align , and inline storage-class modifiers, see the HP 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 HP 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 HP 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, HP recommends that you use the const modifier, because const is standard-conforming and readonly is not.

4.4.3 The _align Modifier

The _align and __align storage-class modifiers have the same semantic meaning. 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.

The _align and __align storage-class modifiers align objects of any of the HP C data types on a specified storage boundary. Use these modifiers in a data declaration or definition.

See the HP C Language Reference Manual for a detailed description of __align and _align .

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 HP 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 and I64 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. HP 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-2).

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, compile with the /G_FLOAT qualifier.

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

When compiling with HP 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 HP C on OpenVMS Alpha systems, if you omit both /G_FLOAT and /FLOAT, the default representation of double variables is G_floating.

When compiling with HP C on OpenVMS I64 systems, the default representation of single and double variables is IEEE_floating. See the /FLOAT qualifier for more information on floating-point representation on I64 systems.

For OpenVMS Alpha and I64 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 and I64 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 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 HP 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 VAX systems, HP C maps the standard C defined long double type to the G_floating or D_floating format.

On OpenVMS Alpha and I64 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.


Previous Next Contents Index