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


Chapter 2
HP C++ Implementation

This chapter discusses the features and characteristics specific to the HP C++ implementation, including pragmas, predefined names, numerical limits, and other implementation-dependent aspects of the language definition.

2.1 Implementation-Specific Attributes

This section describes pragmas, predefined names, and limits placed on the number of characters and arguments used in C++ programs.

2.1.1 #pragma Preprocessor Directive

The #pragma preprocessor directive is a standard method for implementing features that differ from one compiler to the next. This section describes pragmas specifically implemented in the C++ compiler for OpenVMS systems.

The following #pragma directives are subject to macro expansion. A macro reference can occur anywhere after the pragma keyword.
builtins inline linkage 1 use_linkage 1
dictionary noinline module extern_model
member_alignment message define_template extern_prefix


1Not supported; specific to C

This manual displays keywords used with #pragma in lowercase letters. However, these keywords are not case sensitive.

2.1.1.1 #pragma [no]builtins

The #pragma builtins directive enables the C++ built-in functions that directly access processor instructions. If the pragma does not appear in your program, the default is #pragma nobuiltins .

C++ supports the #pragma builtins preprocessor directive for compatibility with VAX C, but it is not required.

2.1.1.2 #pragma define_template Directive

The #pragma define_template directive instructs the compiler to instantiate a template with the arguments specified in the pragma. This pragma has the following syntax:

#pragma define_template identifier

For example, the following statement instructs the compiler to instantiate the template mytempl with the arguments arg1 and arg2 :


#pragma define_template mytempl<arg1, arg2> 

For more information on how to use templates with the #pragma
define_template directive, see Section 5.2.

2.1.1.3 #pragma environment Directive

The #pragma environment directive offers a way to single-handedly set, save, or restore the states of context pragmas. This directive protects include files from contexts set by encompassing programs and protects encompassing programs from contexts that could be set in header files that the encompassing programs include.

On OpenVMS systems, the #pragma environment directive affects the following pragmas:

#pragma member_alignment
#pragma message
#pragma extern_model
#pragma extern_prefix

This pragma has the following syntax:

#pragma environment command_line
#pragma environment header_defaults
#pragma environment restore
#pragma environment save

command_line

Sets, as specified on the command line, the states of all the context pragmas. You can use this pragma to protect header files from environment pragmas that take effect before the header file is included.

header_defaults

Sets the states of all the context pragmas to their default values. This is almost equivalent to the situation in which a program with no command line options and no pragmas is compiled; except that this pragma sets the pragma message state to #pragma nostandard , as is appropriate for header files.

save

Saves the current state of every pragma that has an associated context.

restore

Restores the current state of every pragma that has an associated context.

Without requiring further changes to the source code, you can use #pragma environment to protect header files from things like language extensions and enhancements that might introduce additional contexts.

A header file can selectively inherit the state of a pragma from the including file and then use additional pragmas as needed to set the compilation to non-default states. For example:


#ifdef __PRAGMA_ENVIRONMENT 
#pragma __environment save  (1)
#pragma __environment header_defaults (2)
#pragma member_alignment restore (3)
#pragma member_alignment save (4)
#endif 
. 
.  /* contents of header file */ 
. 
#ifdef __PRAGMA_ENVIRONMENT 
#pragma __environment restore 
#endif 

In this example:

  1. Saves the state of all context pragmas
  2. Sets the default compilation environment
  3. Pops the member alignment context from the #pragma member_alignment stack that was pushed by #pragma __environment save (restoring the member alignment context to its preexisting state)
  4. Pushes the member alignment context back onto the stack so that the #pragma __environment restore can pop the entry off

Thus, the header file is protected from all pragmas, except for the member alignment context that the header file was meant to inherit.

2.1.1.4 #pragma extern_model Directive

The #pragma extern_model directive controls the compiler's interpretation of data objects that have external linkage. You can use this pragma to select the global symbol model to use for extern s. The default is the relaxed refdef model.

Note

Take great care when using the non-default extern_model . The main purpose of extern_model is to allow C++ to share global data with code written in other languages. Declarations that cause data to be allocated according to the C++ object model, that is, declarations for other than POD (Plain Old Data) objects, cannot generally be shared reliably with other languages, and should only appear in regions of source that are subject to the default extern_model of relaxed_refdef .

Within regions of source subject to an extern_model other than relaxed_refdef , declarations that allocate data with names visible to the linker should be limited exclusively to POD types. In particular, declaring a C++ class containing a static data member within such a region may produce unintended behavior.

After you select a global symbol model with #pragma extern_model , the compiler treats all subsequent declarations of objects of the extern storage class accordingly, until it encounters another #pragma extern_model directive.

The global symbol models are as follows:

  • Common block model
    In this model, all declarations are definitions and the linker combines all definitions with the same name into one definition. For Fortran program units, such extern variables appear as named COMMON blocks. The syntax is as follows:

    #pragma extern_model common_block [(no)shr]


    The shr and noshr keywords determine whether the psects created for definitions are marked as shared or not shared. Fortran COMMON blocks normally have the shared attribute. If neither keyword is specified, the pragma acts as if noshr was specified.

    Note

    The C language permits objects declared with the const type qualifier to be allocated in read-only memory, and when the C compiler allocates a psect for a const object, it marks that section as read-only.

    This is not compatible with the C++ conventions because the C++ language permits objects with static storage duration to be initialized with values computed at run-time (before the main function gains control). When the C++ compiler allocates a psect for such a declaration, it marks the psect writable. Normally, only one compilation (the one responsible for initialization) will allocate a psect for a const object, and there is no problem.

    But under the common_block extern model, the compilers will always allocate a psect for such a declaration, leading to a "conflicting attributes" warning from the linker if the same const -qualified declaration is processed by both C and C++. It is best to avoid use of the common_block extern model when const objects with external linkage are shared between C and C++. If the common_block model must be used, then the const type qualifier should be removed (for example, by preprocessor conditionals) from the declaration processed by the C compiler.
  • Relaxed refdef model
    This model is the default. Some declarations are references and some are definitions. Multiple uninitialized definitions for the same object are allowed and resolved into one by the linker. However, a reference requires that at least one definition exists. The syntax is as follows:

    #pragma extern_model relaxed_refdef [(no)shr]


    The shr and noshr keywords determine whether the psects created for definitions are marked as shared or not shared. If neither keyword is specified, the pragma acts as if noshr was specified.

  • Strict refdef model
    In this model, some declarations are references and some are definitions. It requires exactly one definition in the program for each symbol referenced. The syntax is as follows:

    #pragma extern_model strict_refdef ["name"] [(no)shr]


    If specified, name in quotes is the name of the psect for any definition.
    The shr and noshr keywords determine whether the psects created for definitions are marked as shared or not shared. Neither keyword can be specified unless a name for the psect is given. If neither keyword is specified, the pragma acts as if noshr was specified.

  • Globalvalue model
    This model is like the strict refdef model except that these global objects have no storage; instead, global objects are link-time constant values. The syntax is as follows:

    #pragma extern_model globalvalue

  • Save
    This pragma pushes the current extern model of the compiler onto a stack. The stack records all the information associated with the extern model, including the shr and noshr states and any quoted psect name.
    The number of entries allowed in the extern_model stack is limited only by the amount of memory available to the compiler. The syntax is as follows:

    #pragma extern_model save

  • Restore
    This pragma pops the extern model stack of the compiler. The compiler's extern model is set as the state just popped off the stack. The stack records all the information associated with the extern model, including the shr and noshr states and any quoted psect name.
    A warning message is issued if the program tries to pop an empty stack. Attempting to pop an empty stack does not change the compiler's extern state. The syntax is as follows:

    #pragma extern_model restore

The #pragma extern_model directive has the following syntax:

#pragma extern_model model_spec [attr[,attr]...]

model_spec is one of the following:

common_block
relaxed_refdef
strict_refdef "name"
strict_refdef (No attr specifications allowed)
globalvalue (No attr specifications allowed)

[attr[,attr]...] are optional psect attribute specifications chosen from the following (at most one from each line):

gbl lcl (Not allowed with relaxed_refdef )
shr noshr
wrt nowrt
pic nopic (Not meaningful for Alpha)
ovr con
rel abs
exe noexe
vec novec
For OpenVMS Alpha systems: 0 byte 1 word 2 long 3 quad 4 octa 5 6 7 8 9 10 11 12 13 14 15 16 page
For OpenVMS VAX systems: 2 long 3 quad 4 octa 9 page

The last line of attributes are numeric alignment values. When a numeric alignment value is specified on a section, the section is given an alignment of two raised to that power.

On OpenVMS Alpha systems, the strict_refdef "name" extern_model can also take the following psect attribute specifications:

  • noreorder --- causes variables in the section to be allocated in the order they are defined.
  • natalgn --- has no effect on OpenVMS systems.
    It does, however, change the behavior on Tru64 UNIX systems: when specified, natalgn causes the global variables defined within the section to be allocated on their natural boundary. Currently, all global variables on Tru64 UNIX systems are allocated on a quadword boundary. When the natalgn attribute is specified, the compiler instead allocates the variable on an alignment that is natural for its type ( char s on byte boundaries, int s on longword boundaries, and so on).
    Specifying the natalgn attribute also enables the noreorder attribute.

    Note

    Use of the natalgn attribute can cause a program to violate the Tru64 UNIX Calling Standard. The calling standard states that all global variables must be aligned on a quadword boundary. Therefore, variables declared in a natalgn section should only be referenced in the module that defines them.

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

Table 2-1 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).
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.

See the OpenVMS Linker Utility Manual for more complete information on each.

The default attributes are: noshr , rel , noexe , novec , nopic .

For strict_refdef , the default is con . For common_block and relaxed_refdef , the default is ovr .

The default for wrt / nowrt is determined by the first variable placed in the psect. If the variable has the const type qualifier (or the readonly modifier), the psect is set to nowrt . Otherwise, it is set to wrt .

Restrictions on Setting Psect Attributes

Be aware of the following restriction on setting psect attributes.

The #pragma extern_model directive does not set psect attributes for variables declared as tentative definitions in the relaxed_refdef model . A tentative definition is one that does not contain an initializer. For example, consider the following code:


#pragma extern_model relaxed_refdef long 
int a; 
int b = 6; 
#pragma extern_model common_block long 
int c; 

Psect A is given octaword alignment (the default) because a is a tentative definition. Psect B is correctly given longword alignment because it is initialized and is, therefore, not a tentative definition. Psect C is also given longword alignment because it is declared in an extern_model other than relaxed_refdef .

Note

The psect attributes are normally used by system programmers who need to perform declarations normally done in macro. Most of these attributes are not needed in normal C programs. Also, notice that the setting of attributes is supported only through the #pragma mechanism, and not through the /EXTERN_MODEL command-line qualifier.

2.1.1.5 #pragma extern_prefix Directive

The #pragma extern_prefix directive controls the compiler's synthesis of external names, which the linker uses to resolve external name requests. When you specify #pragma extern_prefix with a string argument, the compiler prepends the string to all external names produced by the declarations that follow the pragma specification.

This pragma is useful for creating libraries where the facility code can be attached to the external names in the library.

The syntax is as follows:

#pragma extern_prefix
  • "string"
  • save
  • restore

"string"

Prepends the quoted string to external names in the declarations that follow the pragma specification.

save

Saves the current pragma prefix string.

restore

Restores the saved pragma prefix string.

The default external prefix, when none has been specified by a pragma, is the null string. The recommended use is as follows:

#pragma extern_prefix save
#pragma extern_prefix " prefix-to-prepend-to-external-names "
...some declarations and definitions ...
#pragma extern_prefix restore

When an extern_prefix is in effect and you are using #include to include header files, but do not want the extern_prefix to apply to extern declarations in the header files, use the following code sequence:

#pragma extern_prefix save
#pragma extern_prefix ""
#include ...
#pragma extern_prefix restore
Otherwise, the external identifiers for definitions in the included files will be prepended with the external prefix.

All external names prefixed with a nonnull string using #pragma extern_prefix are converted to uppercase letters regardless of the setting of the /NAMES qualifier.

The compiler treats #pragma extern_prefix independently of the /PREFIX_LIBRARY_ENTRIES qualifier. The /PREFIX_LIBRARY_ENTRIES qualifier affects only ANSI and C Run-Time Library (RTL) entries; the extern_prefix pragma affects external identifiers for any externally visible name.

2.1.1.6 #pragma function Directive

The #pragma function directive specifies that calls to the specified functions will occur in the source code. You normally use this directive in conjunction with #pragma intrinsic , which affects specified functions that follow the pragma directive. The effect of #pragma intrinsic on a given function continues to the end of the source file or until a #pragma function directive occurs, specifying that function.

The #pragma function directive has the following syntax:

#pragma function (function1[,function2, ...])
#pragma function ()

You cannot specify this pragma with empty parentheses. To disable all intrinsic functions, specify the /OPTIMIZE=NOINTRINSICS qualifier on the command line.

2.1.1.7 #pragma include_directory Directive

The effect of each #pragma include_directory is as if its string argument (including the quotes) were appended to the list of places to search that is given its initial value by the /INCLUDE_DIRECTORY qualifier, except that an empty string is not permitted in the pragma form.

The #pragma include_directory directive has the following syntax:

#pragma include_directory <string-literal>

This pragma is intended to ease DCL command-line length limitations when porting applications from POSIX-like environments built with makefiles containing long lists of -I options that specify directories to search for headers. Just as long lists of macro definitions specified by the /DEFINE qualifier can be converted to #define directives in a source file, long lists of places to search specified by the /INCLUDE_DIRECTORY qualifier can be converted to #pragma include_directory directives in a source file.

Note that the places to search, as described in the help text for the /INCLUDE_DIRECTORY qualifier, include the use of POSIX-style pathnames, for example "/usr/base" . This form can be very useful when compiling code that contains POSIX-style relative pathnames in #include directives. For example, #include <subdir/foo.h> can be combined with a place to search such as "/usr/base" to form "/usr/base/subdir/foo.h" , which will be translated to the filespec "USR:[BASE.SUBDIR]FOO.H"

This pragma can appear only in the main source file or in the first file specified on the /FIRST_INCLUDE qualifier. Also, it must appear before any #include directives.

2.1.1.8 #pragma [no]inline Directive

The #pragma inline directive expands function calls inline. The function call is replaced with the function code itself.

The #pragma inline directive has the following syntax:

#pragma inline (id,...) #pragma noinline (id,...)

If a function is named in an inline directive, calls to that function will be expanded as inline code, if possible.

If a function is named in a noinline directive, calls to that function will not be expanded as inline code.

If a function is named in both an inline and a noinline directive, an error message is issued.

For calls to functions named in neither an inline nor a noinline directive, C++ expands the function as inline code whenever appropriate as determined by a platform-specific algorithm.

2.1.1.9 #pragma intrinsic Directive

The #pragma intrinsic directive specifies that calls to the specified functions are intrinsic. Intrinsic functions are functions in which the compiler generates optimize code in certain situations, possibly avoiding a function call.

The #pragma intrinsic directive has the following syntax:

#pragma intrinsic (function1[,function2, ...])

You can use this directive to make intrinsic the default form of functions that have intrinsic forms. The following functions have intrinsic forms:


abs 
fabs 
labs 
alloca 

You can use the #pragma function directive to override the #pragma intrinsic directive for specified functions.

The function must have a declaration visable at the time the compiler encounters the #pragma intrinsic directive. The compiler takes no action if the compiler does not recognize the specified function name as an intrinsic.

2.1.1.10 #pragma [no]member_alignment Directive

By default, the compiler for OpenVMS systems aligns structure members so that members are stored on the next boundary appropriate to the type of the member; that is, bytes are on the next byte boundary, words are on the next word boundary, and so on.

You can use the #pragma member_alignment directive to specify structure member alignment explicitly. For example, using #pragma member_alignment aligns a long member variable on the next longword boundary, and it aligns a short member variable on the next word boundary.

Using #pragma nomember_alignment causes the compiler to align structure members on the next byte boundary regardless of the type of the member. The only exception to this is for bit-field members.

If used, the nomember_alignment pragma remains in effect until the compiler encounters the member_alignment pragma.

To save and restore the current setting of the member_alignment pragma, you can use the member_alignment save and member_alignment restore pragmas.

To affect the member alignment of the entire module, use the /MEMBER_ALIGNMENT qualifier. For information about this qualifier, see Section 2.1.1.10.

2.1.1.11 #pragma message Directive

The #pragma message directive controls the kinds of individual diagnostic messages or groups of messages that the compiler issues. Use this pragma to override any command-line options specified by the /WARNINGS qualifier, which affects the types of messages the compiler issues.

Default severities used by the compiler can be changed only if they are informationals, warnings, or discretionary errors. Attempts to change more severe severities are ignored. If a message severity has not been altered by the command line and is not currently being controlled by a pragma, the compiler checks to see whether the message severity should be changed because of the "quiet" state. If not, the message is issued using the default severity.

Error message severities start out with command-line severities applied to default compiler severities. Pragma message severities are then applied. In general, pragma severities override command-line severities, which override default severities. The single exception to this is that command-line options can always be used to downgrade messages. However, command-line qualifiers cannnot be used to raise the severity of messages currently controlled by pragmas.

The #pragma message directive has the following syntax:

#pragma message disable (message-list)
#pragma message enable (message-list)
#pragma message error (message-list)
#pragma message fatal (message-list)
#pragma message informational (message-list)
#pragma message warning (message-list)
#pragma message restore
#pragma message save

disable

Suppresses the compiler-issued messages specified in the message-list argument. The message-list argument can be any one of the following:
  • A single message identifier
  • The keyword ALL (all messages issued by the compiler)
  • A single message identifier enclosed in parentheses
  • A comma-separated list of message identifiers enclosed in parentheses

A message identifier is the name immediately following the message severity code letter. For example, consider the following message:


%CXX-W-MISSINGRETURN, Non-void function "name" does not contain a return 
 statement 

The message identifier is MISSINGRETURN. To prevent the compiler from issuing this message, use the following directive:


#pragma message disable MISSINGRETURN 

The compiler lets you disable a discretionary message if its severity is warning (W), informational (I), or error (E) at the time the message is issued. If the message has severity of fatal (F), the compiler issues it regardless of instructions not to issue messages.

enable

Enables the compiler to issue the messages specified in the message-list argument.

errors

Sets the severity of each message in the message list to Error.

fatals

Sets the severity of each message in the message list to Fatal.

informationals

Sets the severity of each message in the message list to Informational.

warnings

Sets the severity of each message in the message list to Warning.

restore

Restores the saved state of enabling or disabling compiler messages.

save

Saves the current state of enabling or disabling compiler messages.

The save and restore options are useful primarily within header files. See Section 2.1.1.5.

#pragma message performs macro expansion so that you map Version 5.6 message tags to Version 6.0 tags:


...
#if __DECCXX_VER > 60000000 
#define uninit used_before_set 
#endif 
 
#pragma message disable uninit 
int main() 
{ 
  int i,j; 
 
  i=j; 
} 
#pragma message enable uninit 

2.1.1.12 #pragma module Directive

When you compile source files to create an object file, the compiler assigns the first of the file names specified in the compilation unit to the name of the object file. The compiler adds the .OBJ file extension to the object file. Internally, the OpenVMS system (the debugger and the librarian) recognizes the object module by the file name; the compiler also gives the module a version number of 1. For example, given the object file EXAMPLE.OBJ, the debugger recognizes the EXAMPLE object module.

To change the system-recognized module name and version number, use the #pragma module directive.

You can find the module name and the module version number listed in the compiler listing file and the linker load map.

The #pragma module directive is equivalent to the VAX C compatible #module directive.

The #pragma module directive has the following syntax:
#pragma module identifier identifier
#pragma module identifier string

The first parameter must be a valid identifier, which specifies the name of the module to be used by the linker. The second parameter specifies the optional identification that appears on the listing and in the object file. The second parameter must be a valid identifier of no more than 31 characters, or a character-string constant of no more than 31 characters.

2.1.1.13 #pragma once Directive

The #pragma once preprocessor directive specifies that the header file is evaluated only once.

The #pragma once directive has the following format:

#pragma once

2.1.1.14 #pragma pack Directive

The #pragma pack directive specifies the byte boundary for packing member's structures.

The #pragma pack directive has the following format:

#pragma pack [(n)]
#pragma pack(push {, identifier} {, n})
#pragma pack(pop {, identifier} {, n})

n specifies the new alignment restriction in bytes as follows:
1 Align to byte
2 Align to word
4 Align to longword
8 Align to quadword
16 Align to octaword

A structure member is aligned to either the alignment specified by #pragma pack or the alignment determined by the size of the structure member, whichever is smaller. For example, a short variable in a structure gets byte-aligned if #pragma pack (1) is specified. If #pragma pack (2) , (4) , or (8) is specified, the short variable in the structure gets aligned to word.

If #pragma pack is not used, or if n is omitted, packing defaults to 1 for byte alignment.

With the push/pop syntax of this pragma, you can save and restore packing alignment values across program components. This allows you to combine components into a single translation unit even if they specify different packing alignments:

  • Every occurrence of pragma pack with a push argument stores the current packing alignment value on an internal compiler stack. If you provide a value for n, that value becomes the new packing value. If you specify an identifier, a name of your choosing, it is associated with the new packing value.
  • Every occurrence of a pragma pack with a pop argument retrieves the value at the top of the stack and makes that value the new packing alignment. If an empty stack is popped, the alignment value defaults to the /[NO]MEMBER_ALIGNMENT command-line setting, and a warning is issued. If you specify a value for n, that value becomes the new packing value.
    If you specify an identifier, all values stored on the stack are removed from the stack until a matching identifier is found. The packing value associated with the identifier is also removed from the stack, and the packing value that was in effect just before the identifier was pushed becomes the new packing value. If no matching identifier is found, the packing value reverts to the command-line setting, and a warning is issued.

The push/pop syntax of pragma pack lets you write header files that ensure that packing values are the same before and after the header file is encountered. Consider the following example:


// File name: myinclude.h 
// 
#pragma pack( push, enter_myinclude ) 
// Your include-file code ... 
#pragma pack( pop, enter_myinclude ) 
// End of myinclude.h 

In this example, the current packing value is associated with the identifier enter_myinclude and pushed on entry to the header file. Your include code is processed. The #pragma pack at the end of the header file then removes all intervening packing values that might have occurred in the header file, as well as the packing value associated with enter_myinclude , thereby preserving the same packing value after the header file as before it.

This syntax also lets you include header files that might set packing alignments different from the ones set in your code. Consider the following example:


#pragma pack( push, before_myinclude ) 
#include <myinclude.h> 
#pragma pack( pop, before_myinclude ) 

In this example, your code is protected from any changes to the packing value that might occur in <myinclude.h> by saving the current packing alignment value, processing the include file (which may leave the packing alignment with an unknown setting), and restoring the original packing value.

2.1.1.15 #pragma unroll Directive (ALPHA ONLY)

The #pragma unroll preprocessor directive unrolls the for loop that follows it by the number of times specified in unroll_factor. The #pragma unroll directive must be followed by a for statement.

This directive has the following format:

#pragma unroll unroll_factor

The unroll_factor is an integer constant in the range of 0 to 255. If a value of 0 is specified, the compiler ignores the directive and determines the number of times to unroll the loop in its normal way. A value of 1 prevents the loop from being unrolled. The directive applies only to the for loop that follows it, not to any subsequent for loops.

2.1.1.16 #pragma [no]standard Directive

This directive performs operations similar to the save and restore options on #pragma message directive:

  • #pragma standard is the same as #pragma message restore .
  • #pragma nostandard disables all optional messages after doing a #pragma message save operation.

2.1.2 Predefined Macros and Names

The compiler defines the following predefined macros and predefined names. For information on using predefined macros in header files in the common language environment, see Section 3.2.

Table 2-2 Predefined Macros
Macro Description
_BOOL_EXISTS Indicates that bool is a type or keyword
__BOOL_IS_A_RESERVED_WORD Indicates that bool is a keyword
__DATE__ 1 A string literal containing the date of the translation in the form Mmm dd yyyy , or Mmm d yyyy if the value of the date is less than 10
__FILE__ 1 A string literal containing the name of the source file being compiled
__IEEE_FLOAT Identifies floating-point format for compiling the program. The default value is 1 for OpenVMS I64 systems, and 0 for OpenVMS Alpha and VAX systems.
__LINE__ 1 A decimal constant containing the current line number in the C++ source file
__PRAGMA_ENVIRONMENT Indicates that that the pragma environment directive is supported.
__TIME__ 1 A string literal containing the time of the translation in the form of hh:mm:ss
_WCHAR_T Indicates that wchar_t is a keyword


1Cannot be redefined or undefined

Table 2-3 lists names with a defined value of 1.

Table 2-3 Names with a Defined Value of 1
Name Description
__cplusplus 1 Language identification name.
__DECCXX Language identification name.
__VMS System identification
__vms System identification


1Cannot be redefined or undefined

The compiler predefines __VMS ; the C compiler predefines VMS and __VMS . Therefore, C++ programmers who plan to reuse code should check for __VMS .

On OpenVMS Alpha systems, the compiler supports the following predefined macro names.

Table 2-4 Predefined Macros Specific to OpenVMS Alpha Systems
Name Description
__Alpha_AXP System identification name
__ALPHA System identification name
__alpha System identification name
__32BITS Defined when pointers and data of type long are 32 bits on Alpha platforms

The compiler predefines __32BITS when pointers and data of type long are 32 bits on Alpha platforms.

On both UNIX and OpenVMS operating systems, programmers should use the predefined macro __alpha for code that is intended to be portable from one system to the other.

On OpenVMS I64 systems, the compiler supports the following predefined macro names:

Table 2-5 Predefined Macros Specific to OpenVMS I64 Systems
Name Description
__ia64 System identification name
__ia64__ System identification name
__32BITS Defined when pointers and data of type long are 32 bits.

Predefined macros (with the exception of vms_version , VMS_VERSION , __vms_version , __VMS_VERSION , and __INITIAL_POINTER_SIZE ) are defined as 1 or 0, depending on the system (VAX or Alpha processor), the compiler defaults, and the qualifiers used. For example, if you compiled using G_FLOAT format, __D_FLOAT and __IEEE_FLOAT (Alpha processors only) are predefined to be 0, and __G_FLOAT is predefined as if the following were included before every compilation unit:


 #define  __G_FLOAT  1 

These macros can assist in writing code that executes conditionally. They can be used in #elif , #if , #ifdef , and #ifndef directives to separate portable and nonportable code in a C++ program. The vms_version , VMS_VERSION , __vms_version , and __VMS_VERSION macros are defined with the value of the OpenVMS version on which you are running (for example, Version 6.0).

C++ automatically defines the following macros pertaining to the format of floating-point variables. You can use them to identify the format with which you are compiling your program.

__D_FLOAT
__G_FLOAT
__IEEE_FLOAT
_IEEE_FP
__X_FLOAT

The value of __X_FLOAT can be 0 or 1 depending on the floating point mode in effect. You can use the /FLOAT qualifier to change the mode.

Table 2-6 lists predefined version string and version number macros.

Table 2-6 Version String and Version Number Macros
Name Description
__VMS_VERSION 1 Version identification
__vms_version 1 Version identification
__DECCXX_VER 2 Version identification
__VMS_VER 2 Version identification


1The value is a character string.
2The value is an unsigned long int that encodes the version number.

For example, the defined value of __VMS_VERSION on OpenVMS Version 6.1 is character string V6.1 .

You can use __DECCXX_VER to test that the current compiler version is newer than a particular version and __VMS_VER to test that the current OpenVMS Version is newer than a particular version. Newer versions of the compiler and the OpenVMS operating system always have larger values for these macros. If for any reason the version cannot be analyzed by the compiler, then the corresponding predefined macro is defined but has the value of 0. Releases of the compiler prior to Version 5.0 do not define these macros, so you can distinguish earlier compiler versions by checking to determine if the __DECCXX_VER macro is defined.

The following example tests for C++ 5.1 or higher:


#ifdef __DECCXX_VER 
    #if __DECCXX_VER >= 50100000 
        / *Code */ 
    #endif 
#endif 

The following tests for OpenVMS Version 6.2 or higher:


#ifdef __VMS_VER 
    #if __VMS_VER >= 60200000 
        /* code */ 
    #endif 
#endif 

Table 2-7 shows the macro names for the listed command-line options.

Table 2-7 Macros Defined by Command-Line Qualifiers
Command-line Option Macro Name
/ALTERNATIVE_TOKENS __ALTERNATIVE_TOKENS
/ASSUME=GLOBAL_ARRAY_NEW __GLOBAL_ARRAY_NEW
/ASSUME=STDNEW __STDNEW
/DEFINE=__FORCE_INSTANTATIONS (ALPHA ONLY) __FORCE_INSTANTIATIONS
/EXCEPTIONS __EXCEPTIONS
/IEEE_MODE _IEEE_FP
/IMPLICIT_INCLUDE __IMPLICIT_INCLUDE_ENABLED
/L_DOUBLE_SIZE __X_FLOAT
/MODEL=ANSI __MODEL_ANSI
/MODEL=ARM (ALPHA ONLY) __MODEL_ARM
/PURE_CNAME __PURE_CNAME , __HIDE_FORBIDDEN_NAMES 1
/ROUNDING_MODE __BIASED_FLT_ROUNDS
/RTTI __RTTI
/STANDARD=RELAXED __STD_ANSI, __NOUSE_STD_IOSTREAM
/STANDARD=ANSI __STD_ANSI, __NOUSE_STD_IOSTREAM
/STANDARD=ARM __STD_ARM, __NOUSE_STD_IOSTREAM
/STANDARD=CFRONT As of C++ Version 7.1, the CFRONT option is no longer supported.
/STANDARD=GNU __STD_GNU, __NOUSE_STD_IOSTREAM
/STANDARD=MS __STD_MS, __NOUSE_STD_IOSTREAM
/STANDARD=STRICT_ANSI __STD_STRICT_ANSI , __USE_STD_IOSTREAM ,
__PURE_CNAME , __HIDE_FORBIDDEN_NAMES
/STANDARD=STRICT_ANSI /WARNINGS=ANSI_ERRORS __STD_STRICT_ANSI_ERRORS , __PURE_CNAME ,
__HIDE_FORBIDDEN_NAMES
/USING=STD __IMPLICIT_USING_STD
/STANDARD=LATEST __STD_STRICT_ANSI , __USE_STD_IOSTREAM ,
__PURE_CNAME , __HIDE_FORBIDDEN_NAMES
/STANDARD=LATEST
/WARNINGS=ANSI_ERRORS
__STD_STRICT_ANSI_ERRORS , __PURE_CNAME ,
__HIDE_FORBIDDEN_NAMES


1When you compile with HP C using any values of /STANDARD that set strict C standard conformance (ANSI89, MIA, C99, and LATEST), versions of the standard header files are included that hide many identifiers that do not follow the rules. The header file <stdio.h>, for example, hides the definition of the macro TRUE. The compiler accomplishes this by predefining the macro __HIDE_FORBIDDEN_NAMES for the above-mentioned /STANDARD values.

You can use the /UNDEFINE="__HIDE_FORBIDDEN_NAMES" command-line qualifier to prevent the compiler from predefining this macro and, thereby, including macro definitions of the forbidden names.

2.1.3 Translation Limits

The only translation limits imposed in the compiler are as follows:
Limit Meaning
32,767 Bytes in the representation of a string literal. This limit does not apply to string literals formed by concatenation.
8192 Characters in an internal identifier or macro name.
8192 Characters in a logical name.
8192 Characters in a physical source line, on OpenVMS Alpha systems.
1012 Bytes in any one function argument.
512 Characters in a physical source line, on OpenVMS VAX systems.
255 Arguments in a function call. 1
255 Parameters in a function definition. 1
127 Characters in a qualified identifier in the debugger.
31 Significant characters in an external identifier with "C" linkage. A warning is issued if such an identifier is truncated.


1The compiler may add one or two hidden arguments to a function, which reduces to 254 or 253 the number of arguments available to the user.

2.1.4 Numerical Limits

The numerical limits, as defined in the header files <limits.h> and <float.h> are as follows:

  • The number of bits in a character of the execution character set is eight.
  • The representation and set of values for type char and for type signed char are the same. You can change this equivalence from signed char to unsigned char with a command-line option.
  • The representation and set of values for the short type is 16 bits.
  • The representation and set of values for the types int , signed int , and long are the same (32 bits).
  • The representation and set of values for type unsigned int and for type unsigned long are the same (32 bits).
  • The representation and set of values for type double are 64 bits.
  • The representation and set of values for type long double are 128 bits unless the /L_DOUBLE_SIZE=64) qualifier is specified.
    Specifying a different l_double_size than the default size for your particular version of the operating system does not work correctly with the standard library.

Numerical limits not described in this list are defined in The Annotated C++ Reference Manual.

2.1.5 Argument-Passing and Return Mechanisms

The compiler passes arrays, functions, and class objects with a constructor or destructor by reference. All other objects are passed by value.

If a class has a constructor or a destructor, it is not passed by value. In this case, the compiler calls a copy constructor to copy the object to a temporary location, and passes the address of that location to the called function.

If the return value of a function is a class that has defined a constructor or destructor or is greater than 64 bits, storage is allocated by the caller and the address to this storage is passed in the first parameter to the called function. The called function uses the storage provided to construct the return value.

2.2 Implementation Extensions and Features

This section describes the extensions and implementation-specific features of the compiler on OpenVMS systems.

2.2.1 Identifiers

In the compiler, the dollar sign ($) is a valid character in an identifier.

For each external function with C++ linkage, the compiler decorates the function name with a representation of the function's type.

2.2.1.1 External Name Encoding

The compiler uses the external name encoding scheme described in §7.2.1c of The Annotated C++ Reference Manual.

For the basic types, the external name encoding scheme is exactly the same as that described in The Annotated C++ Reference Manual, as follows:
Type Encoding
void v
char c
short s
int i
long l
float f
double d
long double r
... e
bool jb
wchar_t jw

Class names are encoded as described in The Annotated C++ Reference Manual, except that the DEC C++ compiler uses the lowercase q instead of uppercase Q , and denotes the qualifier count as a decimal number followed by an underscore, as follows:
Class Notation Encoding
simple Complex 7Complex
qualified X::YY q2_1x2yy

Type modifiers are encoded as follows:
Modifier Encoding
const k
signed g
volatile w
unsigned u
__unaligned b

Type declarators are encoded as follows:
Type Notation Encoding
array [10] a10_
function () x
pointer * p
pointer to member S::* m1S
reference & n
unnamed enumeration type h

On OpenVMS Alpha systems, the compiler also supports the following data types:
Type Encoding
__int16 ji4
__int32 ji5
__int64 ji6
__f_float jf
__g_float jg
__s_float js
__t_float jt

2.2.1.2 Modifying Long Names

On OpenVMS systems, if an identifier for a function name with C++ linkage exceeds 31 characters, the name is modified as follows:

  1. A unique value is generated by hashing the full decorated name. This seven-character code is appended to the end of the name.
  2. The name is preceded by the cxx$ facility prefix.
  3. The name is truncated in three back-to-front passes, eliminating underscores, then vowels, and then consonants (y is a consonant). A vowel is never removed if the following conditions apply:
    • It occurs as the first character in the fully decorated name.
    • The character before the vowel is either another vowel or is non-alphanumeric.

    The hash code added at the end of the name is not truncated.
    Truncation ceases when the truncated name, combined with the cxx$ facility prefix and the unique radix 32 value at the end, equals 31 characters.

For information on how to view the demangled form of these names, see Section 1.6.

2.2.2 Order of Static Object Initialization

Nonlocal static objects are initialized in declaration order within a compilation unit and in link order across compilation units. On OpenVMS systems, the compiler uses the lib$initialize mechanism to initialize nonlocal static objects.

2.2.3 Integral Conversions

When demoting an integer to a signed integer, if the value is too large to be represented the result is truncated and the high-order bits are discarded.

Conversions between signed and unsigned integers of the same size involve no representation change.

2.2.4 Floating-Point Conversions

When converting an integer to a floating-point number that cannot exactly represent the original value, the compiler rounds off the result of the conversion to the nearest value that can be represented exactly.

When the result of converting a floating-point number to an integer or other floating-point number at compile time cannot be represented, the compiler issues a diagnostic message.

When converting an integral number or a double floating-point number to a floating-point number that cannot exactly represent the original value, rounds off the result to the nearest value of type float .

When demoting a double value to float , if the converted value is within range but cannot exactly represent the original value, the compiler rounds off the result to the nearest representable float value.

the compiler performs similar rounding for demotions from long double to double or float .

2.2.5 Explicit Type Conversion

In C++, the expression T() (where T is a simple type specifier) creates an rvalue of the specified type, whose value is determined by default initialization. According to the The C++ Programming Language, 3rd Edition, the behavior is undefined if the type is not a class with a constructor, but the ANSI/ISO International Standard removes this restriction. With this change you can now write:


    int i=int(); // i must be initialized to 0 

2.2.6 The sizeof Operator

The type of the sizeof operator is size_t . In the header file, stddef.h , the compiler defines this type as unsigned int , which is the type of the integer that holds the maximum size of an array.

2.2.7 Explicit Type Conversion

A pointer takes up the same amount of memory storage as objects of type int or long (or their unsigned equivalents). Therefore, a pointer can convert to any of these types and back again without changing its value. No scaling occurs and the representation of the value is unchanged.

Conversions to and from a shorter integer and a pointer are similar to conversions to and from a shorter integer and unsigned long . If the shorter integer type was signed, conversion fills the high-order bits of the pointer with copies of the sign bit.

2.2.8 Multiplicative Operators

The semantics of the division (/) and remainder (%) operator are as follows:

  • If either operand of the division operator is negative, the compiler truncates the result toward 0 (that is, the smallest integer larger than the algebraic quotient).
  • If either operand of the remainder operator is negative, the result takes the same sign as that of the first operand.

In the following cases of undefined behavior detected at compile time, the compiler issues a warning:

Integer overflow
Division by 0
Remainder by 0

2.2.9 Additive Operators (§r.5.7)

You can subtract pointers to members of the same array. The result is the number of elements between the two array members, and is of type ptrdiff_t . In the header file stddef.h , the compiler defines this type as int .

2.2.10 Shift Operators (§r.5.8)

The expression E1 >> E2 shifts E1 to the right E2 positions. If E1 has a signed type, the compiler fills the vacated high-order bits of the shifted value E1 with a copy of E1 's sign bit (arithmetic shift).

2.2.11 Equality Operators

When comparing two pointers to members, the compiler guarantees equality if either of the following conditions hold:

  • Both pointers are NULL.
  • The same address expression (&) created both pointers.

When comparing two pointers to members, the compiler guarantees inequality if either of the following conditions hold:

  • Only one pointer is NULL.
  • Each pointer produces a different member if applied to the same object.

When created by different address expressions, two pointers to members may compare either as equal or as unequal if they produce the same member when applied to the same object.

2.2.12 Type Specifiers

For variables that are modifiable in ways unknown to the compiler, use the volatile type specifier. Declaring an object to be volatile means that every reference to the object in the source code results in a reference to memory in the object code.

2.2.13 asm Declarations (ALPHA ONLY)

In the compiler, asm declarations produce a compile-time error. As an alternative to asm, you can use built-in functions. See Appendix C for more information.

2.2.14 Linkage Specifications

Specifying linkage other than "C++" or "C" generates a compile-time error.

In object files, the compiler decorates with type information the names of functions with C++ linkage. This permits overloading and provides rudimentary type checking across compilation units. The type-encoding algorithm used is similar to that given in §7.2.1c of The Annotated C++ Reference Manual (see Section 2.2.1.1).

2.2.15 Class Layout

The alignment requirements and sizes of structure components affect the structure's alignment and size. A structure can begin on any byte boundary and occupy any integral number of bytes.

2.2.15.1 Structure Alignment

Structure alignment is controlled by the /MEMBER_ALIGNMENT command-line qualifier or by using the #pragma member_alignment preprocessor directive. If /MEMBER_ALIGNMENT is specified, or implied by default, the maximum alignment required by any member within the structure determines the structure's alignment. When the structure or union is a member of an array, padding is added to ensure that the size of a record, in bytes, is a multiple of its alignment.

Components of a structure are laid out in memory in the order in which they are declared. The first component has the same address as the entire structure. Padding is inserted between components to satisfy alignment requirements of individual components.

If /NOMEMBER_ALIGNMENT is specified, each member of a structure appears at the next byte boundary.

2.2.15.2 Bit-Fields

If /MEMBER_ALIGNMENT is specified, or implied by default, the presence of bit-fields causes the alignment of the whole structure or union to be at least the same as that of the bit-field's base type.

For bit-fields (including zero-length bit-fields) not immediately declared following other bit-fields, their base type imposes the alignment requirements (less than that of type int ). Within the alignment unit (of the same size as the bit-field's base type), bit-fields are allocated from low order to high order. If a bit-field immediately follows another bit-field, the bits are packed into adjacent space in the same unit, if sufficient space remains; otherwise, padding is inserted at the end of the first bit-field and the second bit-field is put into the next unit.

Bit-fields of base type char must be smaller than 8 bits. Bit-fields of base type short must be smaller than 16 bits.

2.2.15.3 Access Specifiers

The layout of a class is unaffected by the presence of access specifiers.

2.2.15.4 Class Subobject Offsets

A class object that has one or more base classes contains instances of its base classes as subobjects. The offsets of nonvirtual base class subobjects are less than the offsets of any data members that are not part of base class subobjects.

The offsets of nonvirtual base classes increase in derivation order. The offset of the first nonvirtual base class subobject of any class is 0. For single inheritance, the address of a class object is always the same as the address of its base class subobject.

If a class has virtual functions, an object of that class contains a pointer to a virtual function table (VFPTR).

If a class has virtual base classes, an object of that class contains a pointer to a virtual base class table (VBPTR).

For a class with no base classes, the offset of a VFPTR or VBPTR is greater than the offset of any data members. Thus, the offset of the first data member of a class with no base classes is 0, which facilitates interoperability with other languages. If the leftmost base class of a subclass has a VFPTR, a VBPTR, or both, and is not virtual, the class and its base class share the table or tables.

The offsets of virtual base class subobjects are greater than the offset of any data member, and increase in the order of derivation of the virtual base classes. In increasing order, a class object contains the following:

  1. Nonvirtual base class subobjects
  2. Data members
  3. VFPTR (if required)
  4. VBPTR (if required)
  5. Virtual base class subobjects

Consider the following example:


class B1 
{ 
 int x[1]; 
}; 
class B2 : virtual B1 
{ 
 int y[2]; 
 virtual int fl(); 
}; 
class B3 : virtual B2, virtual B1 
{ 
 int z[3]; 
 virtual int f2(); 
}; 
class D : B3 
{ 
 int a[4]; 
 virtual int f1(), f2(), f3(); 
}; 

Figure 2-1 shows the layout of an object of D class for this example.

2.2.16 Virtual Function and Base Class Tables

The compiler allocates storage for virtual function tables (VTBLs) and base class tables (BTBLs) using the common block extern model. All references to VTBLs and BTBLs share a single copy. (The compiler specifies the local (LCL) PSECT attribute for these tables. Thus, one copy of each table exists for each program image file.) This means that you need not be concerned with the associations of these tables during compilation, and the compiler command switch +e supplied in other implementations is not needed for HP C++ for OpenVMS systems.

2.2.17 Multiple Base Classes

Within a class object, base class subobjects are allocated in derivation order; that is, immediate base classes are allocated in the order in which they appear in the class declaration.

Figure 2-1 Layout of an Object of D Class


2.2.18 Temporary Objects

Under the following conditions, the compiler creates temporary objects for class objects with constructors:

  • An object is returned from a function.
  • An object is passed as an argument.
  • An object is created using the constructor notation.
  • A user-defined conversion is implicitly used.

Variations in the compiler generation of such temporary objects can adversely affect their reliability in user programs. The compiler avoids introducing a temporary object whenever it discovers that the temporary object is not needed for accurate compilation. Therefore, you should modify or write your programs so as not to depend on side effects in the constructors or destructors of temporary objects.

2.2.18.1 Lifetime of Temporary Objects

Generally the compiler implements destruction of temporary objects at the end of statements. In certain situations, however, temporary objects are destroyed at the end of the expression; they do not persist to the end of the statement. Temporary objects do not persist to the end of statements in expressions that are:

  • In operands of built-in conditional operators ( || and && )
  • In the second or third operand of the ternary operator ( ?: )
  • Operands to the built-in comma operator ( , )

Consider the following example:


struct A { 
  void print(int i); 
  A(); 
  ~A() { } 
}; 
 
struct B { 
  A* find(int i); 
  B(int i); 
  B(); 
  ~B() { } 
}; 
 
void f() { 
  B(8).find(6)->print(6); 
  (*(B(5).find(3))).print(3); 
  return; 
} 

In the first and second statements inside void f() , the compiler destroys the temporary object created in evaluating the expressions B(8) and B(5) after the call to A::print(int) .

2.2.18.2 Nonconstant Reference Initialization with a Temporary Object

If your program tries to initialize a nonconstant reference with a temporary object, the compiler generates a warning. For example:


struct A { 
  A(int); 
}; 
void f(A& ar); 
 
void g() { 
  f(5);  // warning!! 
} 

2.2.18.3 Static Member Functions Selected by Expressions Creating Temporary Objects

When a static member is accessed through a member access operator, the expression on the left side of the dot (.) or right arrow (->) is not evaluated. In such cases, the compiler creates code that calls the static member function to handle the destruction of a class type temporary; the compiler does not create temporary destructor code. For example:


struct A { 
        ~A(); 
        static void sf(); 
}; 
 
struct B { 
        A operator ()() const; 
}; 
 
void f () { 
    B bobj; 
    bobj().sf();        // If 'bobj()' is evaluated, a temporary of 
                        // type 'A' is created. 
} 

2.2.19 File Inclusion

The #include directive inserts external text into the macro stream delivered to the compiler. Programmers often use this directive to include global definitions for use with compiler functions and macros in the program stream.

On OpenVMS systems, the #include directive may be nested to a depth determined by the FILLM process quota and by virtual memory restrictions. The compiler imposes no inherent limitation on the nesting level of inclusion.

In C++ source programs, inclusion of both OpenVMS and most UNIX style file specifications is valid. For example, the following is a valid UNIX style file specification:


nodename!/device/directory/filename.dat.3 

The exclamation point (!) separates the node name from the rest of the specification; slash characters (/) separate devices and directories; periods (.) separate file types and file versions. Because one character separates two segments of the file specification, ambiguity can occur.

The /INCLUDE_DIRECTORY=(pathname,...) qualifier provides an additional level of search for user-defined include files. Each pathname argument can be either a logical name or a legal UNIX style directory in a quoted string. The default is /NOINCLUDE_DIRECTORY.

The qualifier provides functionality similar to the -I option of the cxx command on Tru64 UNIX systems. This qualifier allows you to specify additional locations to search for files to include. Putting an empty string in the specification prevents the compiler from searching any of the locations it normally searches but directs it to search only in locations you identify explicitly on the command line with the /INCLUDE_DIRECTORY and /LIBRARY qualifiers (or by way of the specification of the primary source file, depending on the /NESTED_INCLUDE_DIRECTORY qualifier).

The basic order for searching depends on the form of the header name (after macro expansion), with additional aspects controlled by other command line qualifiers as well as the presence or absence of logical name definitions. The valid possibilities for names are as follows:

  • Enclosed in quotes. For example: "stdio.h"
  • Enclosed in angle brackets. For example: <stdio.h>

Unless otherwise defined, searching a location means that the compiler uses the string specifying the location as the default file specification in a call to an RMS system service (that is, a $SEARCH/$PARSE) with a primary file specification consisting of the name in the #include (without enclosing delimiters). The search terminates successfully as soon as a file can be opened for reading.

Specifying a null string in the /INCLUDE qualifier causes the compiler to do a non-standard search. This search path is as follows:

  1. The current directory (quoted form only)
  2. Any directories specified in the /INCLUDE qualifier
  3. The directory of the primary input file
  4. Text libraries specified on the command line using /LIBRARY

For standard searches, the search order is as follows:

  1. Search the current directory (directory of the source being processed). If angle-bracket form, search only if no directories are specified with /INCLUDE_DIRECTORY.
  2. Search the locations specified in the /INCLUDE_DIRECTORY qualifier (if any).
  3. If CXX$SYSTEM_INCLUDE is defined as a logical name, search CXX$SYSTEM_INCLUDE:.HXX or just CXX$SYSTEM_INCLUDE:., depending on the qualifier /ASSUME=NOHEADER_TYPE_DEFAULT. If nothing is found, go to step 6.
  4. If CXX$LIBRARY_INCLUDE is defined as a logical name, CXX$LIBRARY_INCLUDE:.HXX or CXX$LIBRARY_INCLUDE:., depending on the qualifier /ASSUME=NOHEADER_TYPE_DEFAULT. If nothing is found, go to step 6.
  5. If /ASSUME=HEADER_TYPE_DEFAULT is not specified, search the default list of locations for plain-text copies of compiler header files as follows:
    SYS$COMMON:[CXX$LIB.INCLUDE.CXXL$ANSI_DEF]
    SYS$COMMON:[CXX$LIB.INCLUDE.DECC$RTLDEF_HXX].HXX
    SYS$COMMON:[CXX$LIB.INCLUDE.DECC$RTLDEF].H
    SYS$COMMON:[CXX$LIB.INCLUDE.SYS$STARLET_C].H

    If /ASSUME=HEADER_TYPE_DEFAULT is specified, search the default list of locations for plain-text copies of compiler header files as follows:
    SYS$COMMON:[CXX$LIB.INCLUDE.DECC$RTLDEF_HXX].HXX
    SYS$COMMON:[CXX$LIB.INCLUDE.DECC$RTLDEF].H
    SYS$COMMON:[CXX$LIB.INCLUDE.SYS$STARLET_C].H
    SYS$COMMON:[CXX$LIB.INCLUDE.CXXL$ANSI_DEF]
  6. Search the directory of the primary input file.
  7. If quoted form, and CXX$USER_INCLUDE is defined as a logical name, search CXX$USER_INCLUDE:.HXX or CXX$USER_INCLUDE:., depending on the /ASSUME=NOHEADER_TYPE_DEFAULT qualifier.
  8. Search the text libraries. Extract the simple file name and file type from the #include specification, and use them to determine a module name for each text library. There are three forms of module names used by the compiler:
    1. type stripped:
      The file type will be removed from the include file specification to form a library module name. Examples:
      #include "foo.h" Module name "FOO"
      #include "foo" Module name "FOO"
      #include "foo" Module name "FOO"
    2. type required:
      The file type must be a part of the file name. Examples:
      #include "foo.h" Module name "FOO.H"
      #include "foo" Module name "FOO."
      #include "foo" Module name "FOO."
    3. type optional:
      First an attempt is made to find a module with the type included in the module name. If this is unsuccessful, an attempt is made with the type stripped from the module name. If this is unsuccessful, the search moves on to the next library.

    If /ASSUME=HEADER_TYPE_DEFAULT is specified, the following text libraries are searched in this order:
    Libraries specified on the command line with the /LIBRARY qualifier (all files, type stripped)
    CXX$TEXT_LIBRARY (all files, type stripped)
    DECC$RTLDEF (H files and unspecified files, type stripped)
    SYS$STARLET_C (all files, type stripped)
    CXXL$ANSI_DEF (unspecified files, type stripped)

    Otherwise, these text libraries are searched in this order:
    Libraries specified on the command line with the /LIBRARY qualifier (all files, type optional)
    CXX$TEXT_LIBRARY (all files, type optional)
    CXXL$ANSI_DEF (all files, type required)
    DECC$RTLDEF (H files and unspecified files, type stripped)
    SYS$STARLET_C (all files, type stripped)

    Two text library search examples (stop when something is found):

    Example 1


    #include "foo" 
    

    1. For each library specified via the /LIBRARY qualifier:
      - Look for "FOO."
      - Look for "FOO"
    2. Look for "FOO." in CXX$TEXT_LIBRARY
    3. Look for "FOO" in CXX$TEXT_LIBRARY
    4. Look for "FOO." in CXXL$ANSI_DEF (Do not look for "FOO" because the type is required as part of the module name)
    5. Look for "FOO" in DECC$RTLDEF (not "FOO." because the type must not be part of the module name)
    6. Look for "FOO" in SYS$STARLET_C (not "FOO." because the type must not be part of the module name)

    Example 2


    #include "foo.h" 
    

    1. For each library specified via the /LIBRARY qualifier:
      - Look for "FOO.H"
      - Look for "FOO"
    2. Look for "FOO.H" in CXX$TEXT_LIBRARY
    3. Look for "FOO" in CXX$TEXT_LIBRARY
    4. Look for "FOO.H" in CXXL$ANSI_DEF (Do not look for "FOO" because the type is required as part of the module name)
    5. Look for "FOO" in DECC$RTLDEF (not "FOO.H" because the type must not be part of the module name)
    6. Look for "FOO" in SYS$STARLET_C (not "FOO.H" because the type must not be part of the module name)
    7. If neither CXX$LIBRARY_INCLUDE nor CXX$SYSTEM_INCLUDE is defined as a logical name, then search SYS$LIBRARY:.HXX.

2.2.20 Nested Enums and Overloading

The C++ language allows programmers to give distinct functions the same name, and uses either overloading or class scope to differentiate the functions:


void f(int); 
void f(int *); 
class C {void f(int);}; 
class D {void f(int);}; 

Yet, linkers cannot interpret overloaded parameter types or classes, and they issue error messages if they find more than one definition of any external symbol. C++ compilers, including HP C++, solve this problem by assigning a unique mangled name (also called type safe linkage name) to every function. These unique mangled names allow the linker to tell the overloaded functions apart.

The compiler forms a mangled name, in part, by appending an encoding of the parameter types of the function to the function's name, and if the function is a member function, the function name is qualified by the names of the classes within which it is nested.

For example, for the function declarations at the beginning of this section, the compiler might generate the mangled names f__Xi , f__XPi , f__1CXi , and f__1DXi respectively. In these names, i means a parameter type was int , P means "pointer to", 1C means nested within class C , and 1D means nested within class D .

There is a flaw in the name mangling scheme used by the compiler that can cause problems in uncommon cases. The compiler fails to note in the encoding of an enum type in a mangled name whether the enum type was nested within a class. This can cause distinct overloaded functions to be assigned the same mangled name:


struct C1 {enum E {red, blue};}; 
struct C2 {enum E {red, blue};}; 
 
extern "C" int printf(const char *, ...); 
void f(C1::E x) {printf("f(C1::E)\n");} 
void f(C2::E x) {printf("f(C2::E)\n");} 
 
int main() 
{ 
    f(C1::red); 
    f(C2::red); 
    return 1; 
} 

In the previous example, the two overloaded functions named f differ only in that one takes an argument of enum type C1::E and the other takes an argument of enum type C2::E . Since the compiler fails to include the names of the classes containing the enum type in the mangled name, both functions have mangled names that indicate the argument type is just E . This causes both functions to receive the same mangled name.

In some cases, the compiler detects this problem at compile-time and issues a message that both functions have the same type-safe linkage. In other cases, the compiler issues no message, but the linker complains about duplicate symbol definitions.

If you encounter such problems, you can recompile using the
/DISTINGUISH_NESTED_ENUMS qualifier (ALPHA ONLY). This causes the compiler, when forming a mangled name, to include the name of class or classes within which an enum is nested, thereby preventing different functions from receiving the same the same mangled name.

Because the /DISTINGUISH_NESTED_ENUMS qualifier changes the external symbols the compiler produces, you can get undefined symbol messages from the linker if some modules are compiled with /DISTINGUISH_NESTED_ENUMS and some are compiled without it. Because of this, /DISTINGUISH_NESTED_ENUMS might make it difficult to link against old object files or libraries of code.

If you compile your code with
/DISTINGUISH_NESTED_ENUMS and try to link against a library that was compiled without the /DISTINGUISH_NESTED_ENUMS qualifier, you receive an undefined symbol message from the linker if you attempt to call a function from the library that takes an argument of a nested enum type. The mangled name of the function in the library will be different from the mangled name your code is using to call the function.

Note that the /DISTINGUISH_NESTED_ENUMS qualifier has no meaning on I64 systems because it modifies the behavior of programs compiled with /MODEL=ARM, and that model is not supported on I64 systems.

2.2.21 Guiding Declarations

A guiding declaration is a function declaration that matches a function template, does not introduce a function definition (implies an instantiation of the template body and not a explicit specialization), and is subject to different argument matching rules than those that apply to the template itself---therefore affecting overload resolution. Consider the following example:


template <class T> void f(T) { 
  printf("In template f\n"); 
} 
 
void f(int); 
 
int main() { 
  f(0);      // invokes non-template f 
  f<>(0.0);  // invokes template f 
  return 0; 
} 
 
void f(int) { 
  printf("In non-template f\n"); 
} 

Because there is no concept of guiding declaration in the current version of the C++ International Standard, the function f in the example is not regarded as an instance of function template f . Furthermore, there are two functions named f that take an int parameter. A call of f(0) would invoke the former, while a call of f<>(0) would be required to invoke the latter.

2.3 Alternative Tokens

The compiler supports use of alternative tokens:

/[no]alternative_tokens

Enable use of operator keywords and digraphs to generate tokens as follows:
Operator Keyword Token
and &&
and_eq &=
bitand &
bitor |
compl ~
not !
not_eq !=
or ||
or_eq |=
xor ^
xor_eq ^=
Digraph Token
:> ]
<: [
%> }
<% {
%: #

2.4 Run-time Type Identification

The compiler emits type information for run-time type identification (RTTI) in the object module with the virtual function table, for classes that have virtual function tables.

You can specify the /[NO]RTTI qualifier to enable or disable support for RTTI (runtime type identification) features: dynamic_cast and typeid . Disabling runtime type identification can also save space in your object file because static information to describe polymorphic C++ types is not generated. The default is to enable runtime type information features and generate static information in the object file.

Specifying /NORTTI does not disable exception handling.

The type information for the class may include references to the type information for each base class and information on how to convert to each. The typeinfo references are mangled in the form __T__<class> .

2.5 Message Control and Information Options

The compiler supports the following message control options. The options apply only to warning and informational messages. The ident variable is obtained from the error message.

Indicated messages can specify one or more message identifiers ident or the message group name all .

The default qualifier, /WARNINGS, outputs all enabled informational and warning messages. The /NOWARNINGS qualifier suppresses both the informational and the warning messages.

Message options are processed and take effect in the following order:

/WARNINGS=NOWARNINGS

Disable all warnings.

/WARNINGS=INFORMATIONALS

Enable informationals.

Although /WARNINGS=INFORMATIONALS enables most informationals, we recommend using /WARNINGS=ENABLE=ALL instead.

/WARNINGS=INFORMATIONALS=ALL or (ident,...)

Set the severity of the specified messages to Informational. You can specify ALL, which applies only to discretionary messages. The ALL option also enables informationals that are disabled by default.

With Version 7.1 of the C++ compiler, /WARNINGS=INFORMATIONALS=<tag> no longer enables all other informational messages.

/WARNINGS=WARNINGS=ALL or (ident,...)

Set the severity of the specified messages to Warning. You can specify ALL, which applies only to discretionary messages.

/WARNINGS=[NO]ANSI_ERRORS

Issue error messages for all ANSI violations when in STRICT_ANSI mode. The default is /WARNINGS=NOANSI_ERRORS.

/WARNINGS=ERRORS=ALL or (ident,...)

Set the severity of the specified messages to Error. You can specify ALL, which applies only to discretionary messages.

/WARNINGS=ENABLE=ALL or (ident,...)

Enable all compiler messages, including informational-level messages. Enable specific messages that normally would not be issued when using /QUIET. You can also use this option to enable messages disabled with /WARNINGS=DISABLE.

/WARNINGS=DISABLE=ALL or (ident,...)

Disable message. This can be used for any nonerror message.

/QUIET

Be more like Version 5.n error reporting. Fewer messages are issued using this option.

This is the default in arm mode (/STANDARD=ARM). All other modes default to /NOQUIET.

You can use the /WARNINGS=ENABLE option with this option to enable specific messages normally disabled using /QUIET.

The compiler supports the following message information option, which is disabled by default.

/WARNINGS=[NO]TAGS

Display a descriptive tag with each message. "D" indicates that the message is discretionary and that its severity can be changed from the command line or with a pragma. The tag displayed can be used as the ident variable in the /WARNINGS options.

Example:


$ cxx/warnings=tags t.cxx
f() {} 
^ 
%CXX-W-NOSIMPINT, omission of explicit type is nonstandard ("int" assumed) 
          (D:nosimpint) 
at line number 1 in file CXX$:[SMITH]STD.CXX;1 
 
 
f() {} 
.....^ 
%CXX-W-MISSINGRETURN, non-void function "f" (declared at line 1) should 
          return a value (D:missingreturn) 
at line number 1 in file CXX$:[SMITH]STD.CXX;1 
 
$ cxx /warnings=(notags,disable=nosimpint) t.cxx
f() {} 
.....^ 
%CXX-W-MISSINGRETURN, non-void function "f" (declared at line 1) should 
          return a value 
at line number 1 in file CXX$:[SMITH]STD.CXX;1

Also see the #pragma message preprocessor directive.


Previous Next Contents Index

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