Updated: 21 April 1999 |
Compaq C++
|
Previous | Contents | Index |
This chapter discusses the features and characteristics specific to
Compaq 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 |
This manual displays keywords used with #pragma in lowercase letters. However, these
keywords are not case sensitive.
2.1.1.1 #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.3.
2.1.1.2 #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:
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:
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.3 #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 externs. The default is the relaxed refdef model.
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:
#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.
#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.
#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.
#pragma extern_model globalvalue |
#pragma extern_model save |
#pragma extern_model restore |
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"
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:
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:
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.5 #pragma function Directive (Alpha only)
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.6 #pragma intrinsic Directive (Alpha only)
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.7 #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.7.
2.1.1.8 #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 this is that command line options can always be used to downgrade messages. However, command line options 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 for a single message group as follows:
- all---All messages issued by the compiler
- A single message identifier enclosed in parentheses
- A single message group name enclosed in parentheses
- A comma-separated list of message identifiers and group name (freely mixed) enclosed in parentheses
A message identifier is the name immediately following the message severity code. For example, consider the following message:
%CXX-W-MISSINGRETURN, Non-void function "name" does not contain a return statementThe message identifier is MISSINGRETURN. To prevent the compiler from issuing this message, use the following directive:
#pragma message disable MISSINGRETURNThe 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.4.
#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 |
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.10 #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.11 #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 {, name} {, n}) #pragma pack(pop {, name} {, 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.
2.1.1.12 #pragma [no]standard Directive
This directive performs operations similar to the save and restore options on #pragma message directive:
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.1.
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 value is always 1 for Compaq Tru64 UNIX. |
__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 |
Table 2-2 lists names with a defined value of 1.
Name | Description |
---|---|
__cplusplus 1 | Language identification name. |
__DECCXX | Language identification name. |
__VMS | System identification |
__vms | System identification |
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.
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.
C++ programmers using both UNIX and OpenVMS operating systems should use the predefined macro __alpha for code that is intended to be portable from one system to the other.
Table 2-4 lists predefined 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 |
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 OpenVMS 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 6.2 or higher:
#ifdef __VMS_VER #if __VMS_VER >= 60200000 /* code */ #endif #endif |
Table 2-5 shows the macro names for the listed command-line options.
Command-line Option | Macro Name |
---|---|
/float | __D_FLOAT 1 |
/float | __G_FLOAT 1 |
/IEEE_float | __IEEE_FLOAT |
/IEEE_mode | __IEEE_FP |
/exceptions | __EXCEPTIONS |
/implicit_include | __IMPLICIT_INCLUDE_ENABLED |
/l_double_size | __X_FLOAT 1 |
/assume=global_array_new | __GLOBAL_ARRAY_NEW |
/rounding | __BIASED_FLT_ROUNDS |
/rtti | __RTTI |
/standard=ansi | __STD_ANSI |
/standard=cfront | __CFRONT , __STD_CFRONT |
/standard=ms | __MS , __STD_MS |
/standard=strict_ansi | __STD_STRICT_ANSI |
/standard=strict_ansi/warnings=ansi_errors | __STD_STRICT_ANSI_ERRORS |
/assume=stdnew | __STDNEW |
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. |
The numerical limits, as defined in the header files <limits.h> and <float.h> are as follows:
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 |
On OpenVMS systems, if an identifier for a function name with C++ linkage exceeds 31 characters, the name is modified as follows:
For information on how to view the demangled form of these names, see
Section 1.5.
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, 3nd Edition, the behavior is undefined if the type is not a class with a constructor, but the ANSI working draft removes this restriction. With this change you can now write:
int i=int(); // i must be initialized to 0 |
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:
In the following cases of undefined behavior detected at compile time, the compiler issues a warning:
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:
When comparing two pointers to members, the compiler guarantees inequality if either of the following conditions hold:
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
In the compiler, asm declarations produce
a compile-time error.
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:
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 Compaq C++ for OpenVMS systems.
2.2.17 Multiple Base Classes (§r.10.1)
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
Under the following conditions, the compiler creates temporary objects for class objects with constructors:
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:
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!! } |
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. } |
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 are 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 basic order of 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:
"stdio.h" |
<stdio.h> |
stdio |
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 directive (without enclosing
delimiters). The search terminates successfully as soon as a file can
be opened for reading.
2.2.19.1 Using Quotation Marks
Using quotation marks (" "), the syntax of the #include directive is as follows:
#include "file-spec"
For this form of file inclusion, the compiler performs the following sequence of actions to try to include the named files:
Using angle brackets (<>), the syntax of the #include directive is as follows:
#include <file-spec>
The file-spec is a valid file specification or a logical name. The file specification must not contain more than 255 characters. If the specified file name is neither a valid OpenVMS specification nor a valid UNIX style file specification, the compiler signals an error.
If the compiler encounters the angle-bracket form of file inclusion, it searches directories in the following order for the named files:
sys$common:[cxx$lib.include.cxxl$def_hxx].hxx sys$common:[cxx$lib.include.decc$rtldef_hxx].hxx sys$common:[cxx$lib.include.cxxl$def_h].h sys$common:[decc$lib.include.decc$rtldef].h sys$common:[decc$lib.include.sys$starlet_c].h sys$common:[cxx$lib.include.cxxl$ansi_def]. |
sys$common:[cxx$lib.include.cxxl$ansi_def]. sys$common:[cxx$lib.include.cxxl$def_hxx]. sys$common:[cxx$lib.include.decc$rtldef_hxx]. sys$common:[cxx$lib.include.cxxl$def_h]. sys$common:[decc$lib.include.decc$rtldef]. sys$common:[decc$lib.include.sys$starlet_c]. |
sys$library:cxxl$def_hxx.tlb sys$library:sys$starlet_c.tlb |
sys$library:cxxl$def_h.tlb sys$library:decc$rtldef.tlb sys$library:sys$starlet_c.tlb |
sys$library:cxxl$def_hxx.tlb sys$library:cxxl$def_h.tlb sys$library:decc$rtldef.tlb sys$library:sys$starlet_c.tlb sys$library:cxxl$ansi_def.tlb |
sys$library:sys$starlet_c.tlb |
sys$library:cxxl$ansi_def.tlb sys$library:cxxl$def_hxx.tlb sys$library:cxxl$def_h.tlb sys$library:decc$rtldef.tlb sys$library:sys$starlet_c.tlb |
On OpenVMS systems, specifying the name of a module in a text library is the most efficient way to include files because such modules are indexed and easier to manipulate than files in a directory. However, this format is not portable to other systems.
When including text modules, the syntax of the #include directive is as follows:
#include module-name
You can create a text library with the library command and specify it with the /library qualifier on the command line. If you use a single command to compile more than one compilation unit, you must specify the library within each compilation unit, if needed. For example:
$ cxx sourcea+mylib/library, sourcec+mylib/library |
If you specify more than one library to the compiler, and if the #include directives are not nested, then the compiler searches the libraries in the specified order each time it encounters an #include directive. In the following example, the compiler searches for modules referenced in mylib.tbl first and then in yourlib.tbl:
$ cxx sourcea+mylib/library+yourlib/library |
If you do not specify a library on the command line, or if the compiler cannot find the specified module in any of the specified libraries, it searches text libraries for the named files in the following order (unless the /include_directory qualifier contained an empty string indicating that none of the normally searched locations are to be searched):
cxx$text_library sys$library:cxxl$def_hxx.tlb sys$library:cxxl$def_h.tlb sys$library:decc$rtldef.tlb sys$library:sys$starlet_c.tlb sys$library:cxxl$ansi_def.tlb |
Under the /assume=noheader_type_default qualifier, the order of the list is changed to put the ANSI library immediately after cxx$text_library.
Regardless of the form of the header name on an #include directive, the effect of an empty string in the /include_directory qualifier is as follows:
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 Compaq 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 qualifer. 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.
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 void f(T) { ... } void f(int); // guiding declaration in non strict_ansi mode |
Because there is no concept of guiding declaration in the current
version of the C++ standard, guiding_decls_allowed is FALSE by default. This
means, in the example above, that function f is not regarded as an instance of function
template f. Furthermore, it means that
there are two functions named f that take
an int parameter: the one that is
explicitly declared, and the one that is an instance of the template. A
call of f(0) would invoke the former,
whereas a call of f<>(0) would be
required to invoke the latter.
2.3 Alternative Tokens
The version 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 :> ] <: [ %> } <% { %: #
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, prints all diagnostic 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)
Turns off all warnings./warnings=(informationals)
Turns on informationals./warnings=informationals=all or (ident,...)
Issue all specified messages as informational. You can specify all, which applies only to discretionary messages. The all option also turns on informationals, which are disabled by default./warnings=warnings=all or (ident,...)
Issue all specified messages as warnings. 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,...)
Issue all specified messages as errors. You can specify all, which applies only to discretionary messages./warnings=enable=all or (ident,...)
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
Previous | Next | Contents | Index |
Legal |