Jump to 
content
HP.com Home Products and Services Support and Drivers Solutions How to Buy
»  Contact HP

 

HP C

HP C
User's Guide for OpenVMS Systems


Previous Contents Index

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.

Note

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

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

Table 4-2 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, I64) 32-bit 1.2 * 10 -38 to 3.4 * 10 38 6
double T_floating (ALPHA, I64) 64-bit 2.2 * 10 -308 to 1.8 * 10 308 15
long double X_floating (ALPHA, I64) 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 HP 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.

HP 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 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 HP 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 HP C for OpenVMS Systems on Alpha and Itanium 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.13.

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.

4.7.2 Bit-Field Initialization

The HP C compiler initializes bit fields in structs differently than VAX C does. The following program compiles without error using both compilers but the results are different. HP 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 HP 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 HP 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 HP 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 HP C for OpenVMS Systems.

4.8.1 Attributes of Program Sections

As the HP 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-3 lists the attributes that can be applied to program sections.

Table 4-3 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.


1HP 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.


Previous Next Contents Index

Privacy statement Using this site means you accept its terms
© 2007 Hewlett-Packard Development Company, L.P.