[an error occurred while processing this directive]

HP OpenVMS Systems

C++ Programming Language
Content starts here

Compaq C++
Using Compaq C++ for OpenVMS VAX


Previous Contents Index


Chapter 2
Compaq C++ Implementation

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

2.1 Compatibility with Other C++ Compilers

The Compaq C++ compiler implements the language definition as specified in The Annotated C++ Reference Manual, which is the basis of the currently proposed ANSI C++ standard. This section describes specific accommodations to make programs developed using other C++ products compile more easily under Compaq C++.

To enhance compatibility with other C++ compilers, Compaq C++ supports the /standard qualifier that directs the compiler to interpret the source program according to certain rules followed by other implementations. The currently supported options to this qualifier are:

  • cfront , which improves compatibility with C++ compilers based on the "cfront" C++ translator from AT&T
  • ms , which improves compatibility with C++ compilers based on Microsoft's Visual C++

Although the /standard qualifier instructs the Compaq C++ compiler to interpret your source code according to the implementations of C++ previously listed, the compatablity with these implementations is not complete. The following sections describe the compatibility situations that Compaq C++ recognizes. For clarity, these sections are marked to indicate which compatibility keyword supports the change in interpretation: cfront or ms .

2.1.1 Incomplete friend Declaration (cfront and ms)

Allow the reserved word class , struct , or union to be omitted from a friend statement (contrary to the syntax rules for C++).

For example:


class foo;
class goo {
    friend foo; //"class" is missing; compatibility options allow this
};

2.1.2 Enumerators in an Enumeration Declaration (cfront and ms)

Ignore any extra comma at the end of the last enumerator in an enumeration declaration.

For example:


enum E {a, b, c,};  // Ignore the "," after "c", if cfront or ms is specified

2.1.3 Incomplete Declarations (cfront and ms)

When a class type declaration is left incomplete at the end of a local scope, the incomplete type declaration is hoisted to its outer scope to allow the type to be completed by any subsequent declaration.

For example:


void bar(struct foo *f); // foo is incomplete at the end of the prototype scope,
                         // so hoist it out to the file scope, if cfront or
                         // ms is specified.

struct foo { int i; };   // Now, foo can be completed by this declaration.

void bar(struct foo *f)  // Now, this foo is the same as the one above.
{
    f->i = 1;
}

void main (void) {
    foo r;

    r.i = 2;
    bar(&r);             // Now, type of r is the same as type of f in bar.
}

Another example:


typedef struct st {
    struct test *ptr;  // test is left incomplete at the end of the scope,
                       // so hoist it out to the file scope.
} st;

typedef struct test {  // Now, test is allowed to be completed.
    int a;
} test;

void init_st (st *o)
{
    o->ptr->a = 3;     // Now, the ptr field is considered to be the same
                       // type as test just above.
}

void main (void) {
    st r;
    test t;

    r.ptr = &t;
    t.a = 1;
    init_st(&r);
}

2.1.4 Overloading Resolution and Enumeration Value of Zero (cfront)

When performing overloading resolution, prefer conversion of an enum type object of value 0 to an arithmetic type, to conversion to a pointer type.

For example:


void trans(unsigned int input);  // The first trans
void trans(char* re);            // The second trans

enum inputs{nickle, dime};

void f(void)
{
    trans(nickle); // nickle's value is zero, so cfront prefers the first trans
}

2.1.5 Prefix and Postfix Increment and Decrement Operators (cfront)

When no operator++(int) (or operator--(int) ) are visible, then invoke operator++() (or operator--() ) for postfix increment (or postfix decrement) operations.

The language specifies that the prefix increment and decrement user-defined operators take one argument (the implicit this argument for a member function), whereas the postfix version takes two arguments (an extra int argument).

For example:


class foo
{
    public:
    int operator++();
//  int operator++(int);
    int operator--();
//  int operator--(int);
};

void f(void)
{
    foo j;

    j++;
    ++j;
    j--;
    --j;
}

When /standard=cfront is specified, the j++ and ++j operations both call the int operator++() . Also, the j-- and --j operations call the int operator--() . But, if you uncomment the int operator++(int) and int operator--(int) in the class declaration, then the language-specified operations will be called whether cfront is specified or not.

2.1.6 Explicit Cast to Reference and Conversions (cfront and ms)

Call any constructors or conversion functions as a result of an explicit cast to a reference.

For example:


extern "C" void printf(char *, ...);

struct S2;

struct S1
{
    operator S2&() {printf("%s \n", "operator S2& called");}
};

struct S2 : public S1
{
    print(){printf("%s \n", "print called");}
};

void f(S1 &rs1)
{
    ((S2 &)rs1).print();  // I know this is a pointer to S2.
}

void main(void)
{
    S2 s2;

    f(s2);
}

Without the /standard=cfront qualifier, running the program will print:


print called

But, with the /standard=cfront qualifier, running the program will print:


operator S2& called
print called

2.1.7 Access Rights to Enclosing Class (cfront)

Allow members of an inner class to have the same access rights to the enclosing class as members or friends of the enclosing class.

For example:


class X {
    protected:
 class Y {
 };
 class Z {
     X::Y *y;  // Ok: cfront makes X::Y accessible
 };
};

2.1.8 Static Incomplete Array Data Members (ms)

Allow static array data members with incomplete class components. For example:


struct x;
struct c;
{
   static x a[];  //component x is incomplete, ms allows this.
};
struct x
{
   int j;
}

2.1.9 Address of Member Functions Without Ampersand (&) Address-of Operator (ms)

When supplying the qualified name of a member function in a pointer-to-member context, allow the ampersand (&) address-of operator to be omitted. For example:


class C {
public:
    int f();
};

int (C::*pmf1)() = C::f;        // with ms, OK to refer to member function
                                // without address-of operator
int (C::*pmf2)() = &C::f;       // without ms, ampersand is required

2.1.10 Ignored Visual C++ Keywords (ms)

Recognize certain Visual C++ keywords (such as export ) but ignore them.

2.1.11 Duplication of Type Qualifiers (ms)

Allow the duplication of type qualifiers. For example:


const const int i;

2.2 Implementation-Specific Attributes

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

2.2.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 Compaq C++ compiler for OpenVMS systems.

The #pragma directives are subject to macro expansion. A macro reference can occur anywhere after the pragma keyword.

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

2.2.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.4.

2.2.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:

#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.2.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 extern s. The default is the relaxed refdef model.

After you select a global symbol model with #pragma extern_model , the Compaq C++ 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.

  • 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. This is the model to use for programs that strictly conform to ANSI C standards. 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

2.2.1.4 #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 Compaq C++ 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 Compaq C++ compiler treats #pragma extern_prefix independently of the /prefix_library_entries qualifier. The /prefix_library_entries qualifier affects only ANSI and DEC C Run-Time Library (RTL) entries; the extern_prefix pragma affects external identifiers for any externally visible name.

2.2.1.5 #pragma [no]member_alignment Directive

You can use the #pragma member_alignment directive to explicitly specify structure member alignment. 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 1.2.1.

2.2.1.6 #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.

The #pragma message directive has the following syntax:


#pragma message disable (message-list)
#pragma message enable (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
    check ---All messages about potentially poor coding practices
    portable ---All messages about portability

  • A single message identifier enclosed in parentheses
  • A single message group name enclosed in parentheses
  • A comma-separated list of message identifiers or group names (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
 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 message only if its severity is warning (W) or informational (I) at the time the message is issued. If the message has severity of error (E) or 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.

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.2.1.4.

2.2.1.7 #pragma module Directive

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.2.1.8 #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)]

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.2.1.9 #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.2.2 Predefined Names (§r.16.10)

Compaq C++ 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
__DATE__ A string literal containing the date of the translation, in the form Mmm dd yyyy , or Mmm d yyyy if the day value is less than 10.
__FILE__ A string literal containing the name of the source file being compiled.
__TIME__ A string literal containing the time of the translation, in the form of hh:mm:ss .
__LINE__ A decimal constant containing the current line number in the C++ source file.

Predefined Macros with a Defined Value of 1

The following macros have a defined value of 1:

__cplusplus
__DECCXX
__VMS
__vms

Compaq C++ predefines __VMS ; DEC C predefines VMS and __VMS . Therefore, C++ programmers who plan to reuse code should check for __VMS .

Predefined Macros With Defined Values of 0 or 1

The value of each of the following macros can be 0 or 1, depending on the floating point mode in effect. You can use the /float qualifier to change the mode.

__D_FLOAT
__G_FLOAT

Predefined Version String Macros

For each of the following macros, the defined value is a character string:

__VMS_VERSION
__vms_version

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

Predefined Version Number Macros

For each of the following macros, the defined value is a unsigned long int that encodes the version number:

__DECCXX_VER
__VMS_VER

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. Note that releases of Compaq C++ 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 Compaq 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

2.2.3 Translation Limits

The only translation limits imposed in Compaq C++ 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.2.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 long double and for type double are the same (64 bits).

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

2.2.5 Argument-Passing and Return Mechanisms

Compaq C++ 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.3 Implementation Extensions and Features

This section describes the extensions and implementation-specific features of Compaq C++ on OpenVMS systems. Where appropriate, section numbers shown in parentheses in the headings (for example, §3.4) refer to relevant sections in the reference manual portion of The C++ Programming Language, 2nd Edition.

2.3.1 Identifiers (§r.2.3)

In Compaq C++, 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.3.1.1 External Name Encoding

The Compaq C++ compiler uses the external name encoding scheme described in §7.2.1c of The Annotated C++ Reference Manual, with certain modifications. These modifications are necessary so that the encoding scheme does not depend on case distinction in linker names.

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

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, Compaq C++ 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.3.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.5.

2.3.2 Order of Static Object Initialization (§r.3.4)

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.3.3 Integral Conversions (§r.4.2)

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.3.4 Floating-Point Conversions (§r.4.3 and §r.4.4)

When converting an integer to a floating-point number that cannot exactly represent the original value, Compaq C++ 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 Compaq C++ 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, Compaq C++ 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, Compaq C++ rounds off the result to the nearest representable float value.

Compaq C++ performs similar rounding for demotions from long double to double or float .

2.3.5 Explicit Type Conversion (§r.5.2.3)

In Compaq 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, 2nd 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

2.3.6 The sizeof Operator (§r.5.3.2)

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

2.3.7 Explicit Type Conversion (§r.5.4)

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.3.8 Multiplicative Operators (§r.5.6)

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

  • If either operand of the division operator is negative, Compaq C++ 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 Compaq C++ compiler issues a warning:

Integer overflow
Division by 0
Remainder by 0

2.3.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 , Compaq C++ defines this type as int .

2.3.10 Shift Operators (§r.5.8)

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

2.3.11 Equality Operators (§r.5.10)

When comparing two pointers to members, the Compaq C++ 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 Compaq C++ 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.3.12 Type Specifiers (§r.7.1.6)

For variables that are modifiable in ways unknown to the Compaq C++ 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.3.13 asm Declarations (§r.7.3)

In Compaq C++, asm declarations produce a compile-time error.

2.3.14 Linkage Specifications (§r.7.4)

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

In object files, Compaq C++ 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.3.1.1).

2.3.15 Class Layout (§r.9.2)

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.3.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 (for a description of how the compiler aligns members, see Section 2.2.1.5). 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.3.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.3.15.3 Access Specifiers

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

2.3.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.3.16 Virtual Function and Base Class Tables

Compaq C++ 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.3.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


2.3.18 Temporary Objects (§r.12.2)

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.3.18.1 Lifetime of Temporary Objects

Generally Compaq C++ 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() , Compaq C++ destroys the temporary object created in evaluating the expressions B(8) and B(5) after the call to A::print(int) .

2.3.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.3.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.3.19 File Inclusion (§r.16.4)

The #include directive inserts external text into the macro stream delivered to the Compaq C++ compiler. Programmers often use this directive to include global definitions for use with Compaq C++ 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 Compaq C++ compiler imposes no inherent limitation on the nesting level of inclusion.

In Compaq 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:

  • Enclosed in quotes. For example:


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


    <stdio.h>
    
  • Simply an identifier to be treated as a text-module name. For example:


    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.3.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:

  1. Depending on the /nested_include_directory qualifier:
    1. If /nested_include_directory=include_file (the default) is in effect, search the directory containing the file in which the #include directive itself occurred. The meaning of "directory containing" is: the RMS resultant string obtained when the file in which the #include occurred was opened, except that the file name and subsequent components are replaced by the default file type for headers ( .hxx , or simply . (dot) if the /assume=noheader_type_default qualifier is in effect). The resultant string will not have translated any concealed device logical name.
    2. If /nested_include_directory=primary_file is in effect, search the default file type for headers using the context of the primary source file. This means that just the file type ( .hxx or . (dot)) is used for the default file specification, but that the chain of related file specifications used to maintain the sticky defaults for processing the next top-level source file is also applied when searching for the file to include.
    3. If /nested_include_directory=none is in effect, this step is bypassed.
  2. Search the locations specified in the /include_directory qualifier (if any). A name that can be parsed successfully as a OpenVMS file specification and does not contain an explicit file type or version specification is edited to append the default header file type specification ( .hxx or . (dot)). A file specification containing a slash (/) character is considered to be a UNIX style name. If the name in the #include directive also contains a slash character that is not the first character and is not preceded by a exclamation point (!) character (that is, it is not an absolute UNIX style path name), then the name in the #include directive is appended to the named location, separated by a slash (/) character, before applying the decc$to_vms path-name translation function.
  3. If 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.
  4. If the file is not found, follow the steps described in Section 2.3.19.2.

2.3.19.2 Using Angle Brackets

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:

  1. Search the file location indicated by a slash (/). This is a UNIX style name that can combine only with UNIX names specified explicitly in the #include directive. It causes a specification like <sys/types.h> to be considered first as /sys/types.h , which will be translated to SYS:TYPES.H .
  2. Search the location specified in the /include_directory qualifier, exactly as in step 2 in Section 2.3.19.1.
  3. If cxx$system_include is defined as a logical name, search
    cxx$system_include:.hxx or just cxx$system_include:. , depending on the /assume=noheader_type_default qualifier.
  4. If cxx$library_include is defined as a logical name, and
    cxx$system_include is not defined as a logical name, search
    cxx$library_include:.hxx or cxx$library_include:. , depending on the
    /assume=noheader_type_default qualifier.
  5. If neither cxx$library_include nor cxx$system_include are defined as logical names, then search the default list of locations for plain-text copies of compiler header files as follows:


       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].
    

    If the file is not found, perform the text library search described in step 6, and if that fails, search sys$library:.hxx .
    Under the /assume=noheader_type_default qualifier, the default file type is modified as usual, and in addition, the order of the list is changed to put the ANSI headers first, resulting in the following:


      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].
    

    If the file is not found, perform the text library search described in step 6, and if that fails, search sys$library:. .
  6. Extract the simple file name and file type from the #include specification and use the file name as the module name to search a list of text libraries associated with that file type. For any file type, the initial text libraries searched consist of those named on the command line with /library qualifiers. If the /include_directory qualifier contained an empty string, no further text libraries are searched. Otherwise, cxx$text_library is searched for all file types. If cxx$library_include is defined as a logical name, then no further text libraries are searched. Otherwise, the subsequent libraries searched for each file type are as follows:
    .hxx :


      sys$library:cxxl$def_hxx.tlb
      sys$library:sys$starlet_c.tlb
    
    

    .h :


      sys$library:cxxl$def_h.tlb
      sys$library:decc$rtldef.tlb
      sys$library:sys$starlet_c.tlb
    
    

    . (dot):


      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
    
    

    Any file type other than .hxx , .h , or . (dot):


      sys$library:sys$starlet_c.tlb
    

    Under the /assume=noheader_type_default qualifier, the order of the list is changed to put the ANSI library first for a null file type, as follows:
    . (dot):


      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
    

2.3.19.3 Including Text Modules

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 Compaq C++ 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 .

Note that, 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:


Previous Next Contents Index