[an error occurred while processing this directive]

HP OpenVMS Systems

C++ Programming Language
Content starts here HP C++

HP C++
User's Guide for OpenVMS Systems


Previous Contents Index


Appendix E
Compiler Compatibility

This appendix describes HP C++ compatibility with other C++ compilers, and documents compatibility concerns between the Version 5.n and Version 6.n compilers.

For porting and compatibility between Alpha and I64 systems, see Chapter 4.

HP C++ implements the C++ International Standard, with some differences, as described in the C++ release notes.

This language differs significantly from The Annotated C++ Reference Manual, implemented by the Version 5.n compilers. When switching from a Version 5.n compiler, you might need to modify your source files, especially if you use the default language mode. In addition, language changes can affect the run-time behavior of your programs. If you want to compile existing source code with minimal source changes, compile using the /STANDARD=ARM qualifier option. See Chapter 7 for information on and changes to the Standard Library.

This chapter describes ways to avoid having the compiler reject program code that previously worked with other C++ implementations that adhere less strictly to the C++ language definition. References to applicable portions of The C++ Programming Language, 3rd Edition indicate where you can find additional help.

E.1 Compatibility with Other C++ Compilers

In default mode (/STANDARD=RELAXED), the compiler implements most features of the C++ International Standard, including:

  • Run-time type identification (RTTI), with dynamic_cast and the typeid operator (see Section 2.4)
  • New-style casts ( static_cast , reinterpret_cast , and const_cast
  • Array new and delete

For compatibility with previous versions, the compiler provides the following language mode options:

/STANDARD=RELAXED

Specify this option if you want an ANSI C++ compiler that supports some commonly used extensions and is somewhat less strict than the standard. This is the default compiler mode. Please note that /STANDARD=ANSI is accepted as a synonym for /STANDARD=RELAXED to be compatible with previous compiler versions.

If you want to use RELAXED mode but find that the compiler generates too many diagnostics in that mode, you can use the /QUIET option with the /STANDARD=RELAXED option. The /QUIET option relaxes error checking and suppresses or reduces the severity of many diagnostics. It also suppresses many warnings that are generated in RELAXED mode but were not issued by Version 5.n compilers. For information on message control options, see Section 2.5.

/STANDARD=ARM

Specify this option if you want to compile programs developed using Version 5.n and want to minimize source changes.

HP C++ Version 6.n and higher also provides support for other C++ dialects and language modes. You can specify the following options:

/STANDARD=MS

Specify this option if you want the compiler to accept additional Microsoft Visual C++ extensions.

/STANDARD=STRICT_ANSI

Enforce the ANSI standard strictly but permit some ANSI violations that should be errors to be warnings. To force ANSI violations to be issued with Error instead of Warning severity, use /WARNINGS=ANSI_ERRORS in addition to /STANDARD=STRICT_ANSI.

/STANDARD=LATEST

Use the latest C standard dialect. /STANDARD=LATEST is currently equivalent to /STANDARD=C99, but is subject to change when newer versions of the C standard are released.

With /STANDARD=MS you may also want to specify /QUIET to reduce the number of diagnostic messages generated.

E.2 Compatibility with Version 5.6 and Earlier

This section provides details about differences between the Version 6.n and later compilers, and the Version 5.6 and earlier compilers:

E.2.1 Language Differences

Users should be aware of the following language differences between Version 6.n and higher (denoted simply as Version 6.n in the following list), and previous versions of the compiler.

  • The most important language differences result from the current implementation of the C++ International Standard in the Version 6.n compilers. If you want to compile existing source code with minimal source changes, compile using the /STANDARD=ARM option.
  • Because the Version 6.n compilers perform more error checking than previous versions, they generate significantly more diagnostic messages. However, you can use the /QUIET option to relax error checking and reduce the severity of many di Message Control and Information Options .
  • The following keywords, introduced with the C++ International Standard, are always reserved keywords in all compiler modes:


    bool, const_cast, explicit, export, false, mutable, dynamic_cast, 
    reinterpret_cast, static_cast, true, typeid, typename, wchar_t 
    

    Alternative representation keywords are as follows:


    and, and_eq, bitand, bitor, compl, not, not_eq, or, or_eq, xor, xor_eq 
    
  • Taking the address of a bit field is not allowed in the current version.
  • Creation of temporaries and their lifetimes vary among compiler modes.
  • Macro expansion in pragmas can give different results in the current and previous versions.
  • The following are distinct types in the Version 6.n compilers; they were the same type in previous versions:


    typedef void (*PF)();             // Pointer to an extern "C++" function 
    extern "C" typedef void (*PCF)(); // Pointer to an extern "C" function 
    void f(PF); 
    void f(PCF); 
    
  • Version 6.n does not allow converting a pointer to member from a derived class to a virtual base class.
  • Calling a nonstatic member function through a null pointer is undefined behavior. Certain cases that used to run without errors in previous versions no longer run in the current version. For example:


    #include <iostream.h> 
     
    struct A { 
        int a; 
    }; 
     
    struct D : public virtual A 
    { 
        A* toA(){ return (A*) this; } 
    }; 
     
    main () 
    { 
        D* d = NULL; 
        A* ad = d->toA(); // will ACCVIO 
        if (ad==NULL) cout << "ok"; 
    } 
    
  • In Version 6.n compilers, bool is a built-in type. In previous versions, it is user-defined, typically as int in system header files. Mangling differs in this respect only for functions that have arguments of type bool .
    In Version 6.n compilers, the size of bool is 1. In previous versions, bool is user defined, typically as int with a size of 4.
    In Version 6.n compilers, the size of a boolean expression ( sizeof(a && b) ) is 1. In previous versions, the size is 4, independent of the size of bool .
  • Version 6.n compilers do not cause pragmas to become effective within function bodies when scanning template definitions.
  • Version 6.n compilers do not allow the "virtual" storage class modifier to be used with member function definitions outside a class.
  • Version 6.n compilers do not allow declaration of pointers to members of type void . For example, the following is not allowed:


    typedef void Z::* any_ptom; 
    

E.2.2 Implementation Differences

Users should be aware of the following implementation differences between Version 6.n compilers, and previous versions of the compiler:

  • The automatic template instantiation model is different for Version 6.n, and previous compiler versions. See Section E.2.3 for details.
    It is different yet again for I64 systems. Chapter 5 for details.
  • Version 6.n and higher drops qualifiers on parameters when determining the function type, as dictated by the C++ International Standard. For instance, in the following example, the function declarations are the same function.


         f(const int p1); 
         f(int p1); 
    

    For compatibility with previous versions, if qualifiers are included in function declarations, they are also included in the mangled name. (Note: this is not true for model ANSI or for I64 systems.)
  • Version 6.n differs from previous versions in interpreting undefined behavior, as when incrementing takes effect in this example:


         f(i++, i++); 
    
  • Version 6.n cannot handle a #pragma define_template that spans multiple lines without the backslash ( \ ) delimiter. Version 5.6 can handle this without problems.
  • Version 6.n displays #line number in /PREPROCESS_ONLY output. The previous version displays #number .
  • After encountering an illegal multibyte character sequence, Version 6.n issues a warning diagnostic and continues processing. The previous version issues an error and stops processing.
  • Version 6.n does not support VAX C module include syntax (for example, #include acms$submitter without <> or " " delimiters). The compiler searches text libraries for modules included using the normal include syntax (specifying the " " or <> delimiters) and correctly (according to the C++ standard) rejects #include directives that do not follow this syntax.

E.2.3 Using Templates

The template instantiation model was completely redesigned for C++ Version 6.0. The changes include:

  • Automatic template instantiation now occurs at compile time. Necessary templates are instantiated automatically by the compilation of the source file that needs them and has access to the template definitions.
  • During automatic template instantiation, instantiations are written into the repository as object files. Compilation of instantiations in no longer done at link time.
  • For automatic instantiation, the compiler no longer requires that template declarations and definitions appear in header files.
  • Template.map files are no longer supported as a way to match template declarations and definitions.
  • Several new manual template instantiation pragmas have been added.

The automatic template instantiation model new with Version 6.0 is not directly compatible with previous template instantiation mechanisms. When linking applications using Version 6.0 and later, instantiations might not be resolved from existing Version 5.n repositories. Where possible, it is safest to start fresh with an empty repository and create the required instantiations by compiling all source files. If this is not possible, there are some strategies that can be used to link mixed generation instantiations.

If you used both Version 6.n and Version 5.n to build applications, HP strongly recommends that you use different repositories to contain automatic template instantiations for Version 6.n and Version 5.n compilations. The default repository name is the same for Version 6.n as for prior versions. Thus, if you use Version 6.n with older pre-6.n versions, you should do compilations in a different directory for each compiler or explicitly specify a different repository for each using the /REPOSITORY qualifier.

E.2.3.1 Linking with Version 5.n Instantiations

When linking applications using Version 6.n against instantiations created with Version 5.n, it is necessary to complete the Version 5.n instantiation process, to create instantiation object files. If old_repository is a Version 5.n repository then you would create the Version 5.n instantiation object files by using the Version 5.n cxxlink :


CXXLINK/NOEXE /REPOSITORY=[.old_repository] 
   <Version 5.n object files> 

<Version 5.n object files> are the object files that were created using the Version 5.n compiler; old_repository now contains the instantiation object files. Create a library of these object files as follows:


LIBRARY/CREATE/OBJECT lib_old_repository/LOG 
LIBRARY/INSERT/OBJECT lib_old_repository/LOG 
       [old_repository]*.obj 

When linking using Version 6.n, specify lib_old_repository.olb after all of the Version 5.n object files that are being linked.

E.2.3.2 Linking Version 5.n Applications Against Version 6.n Repositories

In a similar way, you can create a library of Version 6.n instantiation object files to link into a Version 5.n application being linked using C++ Version 5.n. If new_repository is the Version 6.n repository, then a library of the instantiations would be created by:


LIBRARY/CREATE/OBJECT lib_new_repository/LOG 
LIBRARY/INSERT/OBJECT lib_new_repository/LOG [new_repository]*.obj 

When linking using Version 5.n, specify lib_new_repository.olb after all of the Version 6.n object files that are being linked.

E.2.4 Library Differences

Aspects of memory allocation and deallocation have changed from the V5.n and earlier compilers to the Version 6.n compilers. See the description of /[NO]STDNEW and /[NO]GLOBAL_ARRAY_NEW in The C++ Standard Library .

E.3 Using Classes

This section discusses porting issues pertaining to C++ classes.

E.3.1 Friend Declarations

When making friend declarations, use the elaborated form of type specifier. The following code fragment implements the legal and comments out the illegal friend declaration:


class Y; 
class Z; 
class X; 
   //friend Y;  ** not legal 
   friend class Z; // legal 
};      

E.3.2 Member Access

Unlike some older C++ implementations, HP C++ strictly enforces accessibility rules for public , protected , and private members of a base class. For more information, see The C++ Programming Language, 3rd Edition.

E.3.3 Base Class Initializers

Unlike some older C++ implementations, HP C++ requires you to use the base class name in the initializer for a derived class. The following code fragment implements a legal initializer and comments out an illegal initializer:


class Base { 
    // ...
public: 
    Base (int); 
}; 
class Derived : public Base { 
    // ...
public: 
    // Derived(int i) : (i)  {/* ...*/}    ** not legal        
    Derived(int i) : Base(i) {/* ...*/} // ** legal, supplies class name 
}; 

For more information, see The C++ Programming Language, 3rd Edition.

E.4 Undefined Global Symbols for Static Data Members

When a static data member is declared, the compiler issues a reference to the external identifier in the object code, which must be resolved by a definition. The compiler does not support the declaration anachronism shown in The C++ Programming Language, 3rd Edition.

For example, consider the following code fragment:


class C { 
        static int i; 
        }; 
//missing definition 
//int C::i = 5; 
int main () 
{ 
    int x; 
    x=C::i; 
    return 0; 
} 

The compiler does not issue any messages during compilation; however, when you attempt to link a program containing this code, the linker issues an unresolved symbol error message for the variable C::i .

E.5 Functions and Function Declaration Considerations

HP C++ requires the use of function definitions as described in The C++ Programming Language, 3rd Edition. For examples of outdated syntax not allowed in HP C++, see The C++ Programming Language, 3rd Edition.

Because all linkage specifications for a name must agree, function prototypes are not permitted if the function is later declared as an inline function. The following code is an example of such a conflicting function declaration:


int f(); 
inline int f() { return l; } 

In this example, f is declared with both internal and external linkage, which causes a compiler error.

E.6 Using Pointers

This section demonstrates how to use pointers effectively in HP C++.

E.6.1 Pointer Conversions

In HP C++, you cannot implicitly convert a const pointer to a nonconstant pointer. For example, char * and const char * are not equivalent; explicitly performing such a cast can lead to unexpected results.

For more information, see The C++ Programming Language, 3rd Edition.

E.6.2 Bound Pointers

Binding a pointer to a member function with a particular object as an argument to the function is not allowed in HP C++. For more information on the illegality of casting bound pointers, see The C++ Programming Language, 3rd Edition.

E.6.3 Constants in Function Returns

Because the return value cannot be an lvalue, the const keyword in a function return has no effect on the semantics of the return. However, using the const keyword in a function return does affect the type signature. For example:


static int f1( int a, int b) {;} 
const int (* const (f2[])) (int a, int b) = {f1}; 

In this example, the referenced type of the pointer value f1 in the initializer for f2[] is function (signed int, signed int) , which returns signed int . This is incompatible with function (signed int, signed int) , which returns const signed int .

You can omit the const of int because it affects only the constant return signature.

E.6.4 Pointers to Constants

The following example shows a type mismatch between a pointer to a char and a pointer to a const char that some other compilers might not find:


void foo (const char* argv[]) {} 
int main() 
{ 
        static char* args[2] = {"foo","bar"}; 
 
/* In this statement, the referenced type of the pointer value 
 "args" is "pointer to char" which is not compatible with 
 "pointer to const char"'*/ 
 
        foo (args); 
return 0; 
} 

You can correct this example by changing static char to static const char . Use an explicit type cast to get an argument match only if no other option is available; such a cast may break on some C++ implementations.

E.7 Using typedefs

Using a synonym after a class , struct , or union prefix is illegal. Using a synonym in the names for constructors and destructors within the class declaration itself is also illegal.

In the following example, the illegal typedef specifier is commented out:


typedef struct { /* ...*/ } foo; 
// typedef struct foo foobar;             ** not legal 

For more information, see The C++ Programming Language, 3rd Edition.

E.8 Initializing References

HP C++ warns against initializing nonconstant references to refer to temporary objects. The following example demonstrates the problems that can result:


static void f() 
{ 
    int i = 5; 
    i++;        // OK 
    int &ri = 23; 
    ri++;       // In the initializer for ri, the initialization of a 
                // non-const reference requires a temporary for "23". 
} 

The issue of reference initialization arises most often in assignment operators and in copy constructors. Wherever possible, declare all reference arguments as const .

For more information, see The C++ Programming Language, 3rd Edition.

E.9 Using the switch and goto Statements

Branching around a declaration with an explicit or implicit initializer is not legal, unless the declaration is in an inner block that is completely bypassed. To satisfy this constraint, enclose the declaration in a block. For example:


int i; 
 
switch (i) { 
case 1: 
    int l = 0;     //not initialized at this case label 
    myint m = 0;   //not initialized at this case label 
    { 
    int j = 0;     // legal within the braces 
    myint m = 0;   // legal within the braces 
    } 
case 2: 
    break; 
// ...
} 

For more information on using the switch statement, see The C++ Programming Language, 3rd Edition.

E.10 Using Volatile Objects

You must supply the meaning of copy constructing and assigning from volatile objects, because the compiler generates no copy constructors or assignment operators that copy or assign from volatile objects. The following example contains examples of such errors, as noted in the comments:


class A { 
public: 
  A() { } 
  // A(volatile A&) { } 
  // operator=(volatile A&) { return 0; } 
}; 
 
void foo() 
{ 
  volatile A va; 
  A a; 
 
  A cca(va);  // error - cannot copy construct from volatile object 
  a = va;     // error - cannot assign from volatile object 
 
  return; 
} 

For more information, see The C++ Programming Language, 3rd Edition.

E.11 Preprocessing

HP C++ allows identifiers, but not expressions, on the #ifdef preprocessor directive. For example:


// this is not legal 
// #ifdef KERNEL && !defined(__POSIX_SOURCE) 

The following is the legal alternative:


// use this instead 
#if defined(KERNEL) && !defined(__POSIX_SOURCE) 

For more information, see The C++ Programming Language, 3rd Edition.

E.12 Managing Memory

The proper way to manage memory for a class is to overload the new and delete operators. This is in contrast to some older C++ implementations, which let you manage memory through assignment to the this pointer.

For more information, see The C++ Programming Language, 3rd Edition.

Program developers must take care that any user-defined new operators always return pointers to quadword-aligned memory.

E.13 Size-of-Array Argument to delete Operator

If a size-of-array argument accompanies a delete operator, HP C++ ignores the argument and issues a warning. The following example includes an anachronistic use of the delete operator:


int main() 
{ 
        int *a = new int [20]; 
        int *b = new int [20]; 
        delete[20] a;     //old-style; argument ignored, warning issued 
        delete[] b; 
return 0; 
} 

E.14 Flushing the Output Buffer

Do not depend on the newline character (\ n ) to flush your terminal output buffer. A previous stream implementation might have done so, but this behavior is not in conformance with Version 2.0 of the AT&T iostream library. If you want to flush the output buffer, use the endl manipulator or the flush member function.

E.15 Linking

When linking applications, use CXXLINK instead of LINK. See Section 1.3 (ALPHA ONLY) and Section 1.4 (I64 ONLY).

E.16 Incrementing Enumerations

Some other C++ implementations let you perform integer arithmetic, including ++, on enumerated types; HP C++ does not allow this.

E.17 Guidelines for Writing Clean 64-Bit Code

Paying careful attention to data types can ensure that your code works on both 32-bit and 64-bit systems. Use the following guidelines to write clean 64-bit code:

  • Variables that should be 32 bits in size on both 32-bit systems and 64-bit OpenVMS Alpha systems should be declared as int (not long ).
  • If you want 32-bit variables on a 32-bit system and an OpenVMS system, declare them as int .
  • A 64-bit number on OpenVMS must be declared as __int64 or long long .
  • Remember that register variables and unsigned variables default to int (32 bits).
  • Constants are 32-bit quantities by default. Performing shift operations or bit operations on constants will give 32-bit results. You must add L to the constant to get a 64-bit result. For example:


    long foo, bar; 
    foo = 1L << bar; 
    
  • Assigning to a char is not atomic on OpenVMS Alpha systems. You will get a load of 32 or 64 bits, followed by byte operations to extract, mask, and shift the byte, followed by a store of 32 or 64 bits.
  • Bit-fields declared as int on OpenVMS Alpha systems generate load/store 32 bits. Bit-fields declared as long on OpenVMS Alpha systems generate load/store 64 bits.
  • If you do not explicitly declare the formal parameters to functions, their sizes may not match the caller sizes. The default is int , which truncates 64-bit addresses.
  • The %d and %x format specifiers print 32 bits of data. Use %Ld or %Lx with printf to print 64 bits of data. You can use %p on both 32- and 64-bit systems to print the value of pointers.


Index Contents