HP OpenVMS Systems

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

HP C++
User's Guide for OpenVMS Systems


Previous Contents Index


Chapter 4
Porting to I64 Systems

This chapter describes some of the differences and restrictions you might encounter when porting the HP C++ compiler to an I64 system. For a summary of new and changed features supported by this version of the compiler on both OpenVMS Alpha and I64 systems, see the Preface of this manual. For any known issues, see the C++ release notes.

HP C Version 7.1 for OpenVMS I64 uses a new technology base that differs substantially from HP C++ for OpenVMS Alpha and HP C for OpenVMS I64. Although a great deal of work has been done to make it highly compatible with HP C++ for OpenVMS Alpha, there are a number of differences that you will likely notice. Among them are:

  • Resource requirements.
    Programs will usually use more memory, both at compile time and at run time. See Section 4.1.2.
  • Floating-point behaviors.
    The default on I64 systems is /FLOAT=IEEE/IEEE_MODE=DENORM_RESULTS. Consistent use of qualifiers across compilations is required. See Section 4.1.6.
  • Simplified instantiation without repository. See Section 4.1.9.
  • No inline assembly language. See Section 4.1.7.
  • String literal type change.
    For standards-compliance and link compatiblity between compiler dialects, ordinary string literals now have the type "array of const char" in all compiler dialects on I64 systems in all compiler modes and on Alpha systems in /MODEL=ANSI mode.
    In /MODEL=ARM mode on Alpha systems, string literals are of type "array of char" in all compiler dialects.

4.1 Compiler Considerations

This section describes porting considerations for the C++ compiler for OpenVMS I64 systems. See Section 4.2 for considerations for the standard library, language run-time support library, and class library.

4.1.1 Messages

The move from Alpha systems to I64 systems may cause some minor differences in certain compiler diagnostics that are signaled from the code generator. As a result, diagnostics for unreachable code and fetches of uninitialized variables might be different on the two platforms. In addition to a change in message text, some conditions detected on one platform might not be detected on the other.

There have also been some changes in the /WARNINGS qualifier for both platforms. These include bug fixes and improved compatibility with the C compiler. For a summary of these changes, see the New and Changed Features section of the Preface.

4.1.2 Quotas

The C++ compiler for I64 systems is built from a different code base than the C++ compiler for Alpha systems, and that code base is larger than the code base for Alpha. Also, I64 images tend to be somewhat larger than Alpha images in general. Image size mostly affects working-set size and the amount of pagefile quota needed to execute an image without exhausting virtual memory. If you find that programs that compile and run successfully on Alpha run out of memory on I64 systems (either during compilation or when run), you probably need to increase your pagefile quota. There are no specific guidelines at this time. You might start by doubling the quota that was sufficient on Alpha, and then use a "binary-search" approach to arrive at a better quota value for I64 systems (doubling again, or halving the increment, until your biggest programs and compilations have just enough memory, and then adding an appropriate safety margin).

4.1.3 Dialect Changes

Some of the compiler dialects (options to the /STANDARD qualifier) have been updated to reflect the most recent behaviors of the compilers that the dialect is attempting to match. Other changes involve the removal of less significant or undesirable compatibility features.

4.1.4 ABI/Object Model changes

The object model and the name mangling scheme used by the C++ compiler on I64 systems are different from those used on Alpha systems (different from both /MODEL=ARM and /MODEL=ANSI). The I64 compiler uses the interface described by the I64 Application Binary Interface (ABI).

See http://www.codesourcery.com/cxx-abi/abi.html for a draft description of the ABI specification.

The C++ compiler has some additional encoding rules that are applied to symbol names after the ABI name mangling is determined. All symbols with C++ linkage have CRC encodings added to the name, are uppercased and shorten to 31 characters if necessary. Since the CRC is computed before the name is uppercased, the symbol name is case-sensitive even though the final name is in uppercase. /NAMES=AS_IS and /NAMES=UPPER are not applicable to these symbols.

All symbols without C++ linkage will have CRC encodings added if they are longer then 31 characters and /NAMES=SHORTEN is specified. Global variables with C++ linkage are treated as if they have non-C++ linkage for compatibility with C and older compilers.

4.1.5 Command-Line Qualifiers

This section describes C++ command-line qualifier differences to be aware of on I64 systems.

Qualifiers/Features Not Supported on I64 Systems

The following command-line qualifiers and features are not supported on C++ for I64 systems, and are diagnosed by default because ignoring them is likely to alter program behavior:

  • Comma lists are not supported. Their use provokes a fatal error.
  • /INSTRUCTION_SET=NOFLOATING_POINT is not available on I64 systems. If it is specified, a warning message is issued, and /INSTRUCTION_SET=FLOATING_POINT is used.
  • /L_DOUBLE_SIZE=64 is not available on I64 systems. If it is specified, a warning message is issued, and /L_DOUBLE_SIZE=128 is used.

Changed/Ignored Qualifiers

A number of other qualifiers not supported on I64 systems are, by default, silently ignored by the compiler. These qualifiers fall into two groups:

  • Qualifiers that should not alter the behavior of a correct program and so, if ignored, should have no visible effect. Qualifiers that enable optimizations typically have this characteristic.
  • Qualifiers that might affect program behavior but, if ignored, produce no significant change in the vast majority of programs. Examples of qualifiers in this category are /NORTTI (the runtime information is always generated) and /MODEL=ARM (the ANSI model is functionally superior, and binary compatibility with existing object code is not an issue for the OpenVMS I64 platform).

Two optional compiler messages can be enabled to diagnose most of these cases:

  • The QUALNA message diagnoses uses of the first group.
  • The QUALCHANGE message diagnoses uses of the second group.

If you encounter porting problems, compile /WARN=ENABLE=QUALCHANGE to determine if a qualifier change might be affecting your application.

If you wish to clean up your build scripts to remove extraneous qualifiers that are not meaningful on I64 systems, you can enable the QUALNA message.

A list of these qualifiers follows:

  • /ARCHITECTURE=option
    An additional keyword has been added: ITANIUM2.
    If an Alpha keyword (EV4, EV5, EV56, PCA56, EV6, EV68, EV7) is specified for option, it is ignored.
  • /ASSUME
    The following /ASSUME options are ignored on I64 systems and should not cause any behavior changes:
    NORTTI_CTORVTBLS
    NOPOINTERS_TO_GLOBALS
    TRUSTED_SHORT_ALIGNMENT
    WHOLE_PROGRAM
  • /CHECK=UNINITIALIZED_VARIABLES
    This qualifier has no effect in this version of the compiler.
  • /DEBUG
    The following debug options are ignored:
    /DEBUG=NOSYMBOLS
    /DEBUG=NOTRACEBACK
  • /DISTINGUISH_NESTED_ENUMS
    This qualifier only modified the behavior of programs compiled with /MODEL=ARM. Since that model is not supported on the I64 platform, this qualifier is meaningless.
  • /EXCEPTIONS=NOCLEANUP
    The NOCLEANUP keyword for the /EXCEPTIONS qualifier is ignored.
  • /EXCEPTIONS=IMPLICIT
    The IMPLICIT keyword for the /EXCEPTIONS qualifier is ignored.
  • /FLOAT
    The default for /FLOAT on OpenVMS I64 systems is IEEE_FLOAT.
    See Section 4.1.6 for more information about floating-point behavior on I64 systems.
  • /IEEE_MODE
    The default for /IEEE_MODE on I64 systems is DENORM_RESULTS, which generates infinities, denorms, and NaNs without exceptions.
    On OpenVMS Alpha systems, the default for /IEEE_MODE when using /FLOAT=IEEE_FLOAT is FAST, which causes a FATAL error for exceptional conditions such as divide-by-zero and overflow.
    See Section 4.1.6 for more information.
  • The /MODEL=ARM qualifier is treated the same as the default /MODEL=ANSI (except for the optional QUALCHANGE diagnostic).
  • /OPTIMIZE
    There are several changes to the /OPTIMIZE qualifier:
    • On I64 systems, for /OPTIMIZE=INLINE, the keywords AUTOMATIC and SPEED do the same thing.
      Also, the ALL keyword does not necessarily result in every possible call being inlined, as it does on Alpha systems.
    • The /OPTIMIZE=TUNE qualifier takes a new keyword: ITANIUM2, which is the default at this time. If you specify an Alpha keyword, it is ignored.
    • The /OPTIMIZE=UNROLL=n qualifier is not very useful on I64 systems. Because of this, specifying an unroll value greater than 0 is simplified to mean that simple loop unrolling is enabled. On I64 systems, the user does not have the ability to control the number of times a loop is unrolled.
    • /OPTIMIZE=LIMIT_INLINE is ignored.
  • /TEMPLATE
    See Section 4.1.9 for information on template instantiation.
  • /SHOW=STATISTICS
    The /SHOW=STATISTICS qualifier is ignored at this time.
  • /STANDARD=CFRONT
    The /STANDARD=CFRONT qualifier is no longer available. If it is specified, the compiler issues a warning message and uses the default dialect, /STANDARD=ANSI.

New Qualifiers

The following command-line qualifier is new for C++ Version 7.1:

  • /[NO]PURE_CNAME
    This qualifier affects insertion of the names into the global namespace by <cname> headers.
    In /PURE_CNAME mode, the <cname> headers insert the names into the std namespace only, as defined by the C++ Standard, and the __PURE_CNAME macro is predefined by the compiler.
    In /NOPURE_CNAME mode, the <cname> headers insert the name into the std namespace and also into the global namespace.
    The default depends on the standard mode:
    • In /STANDARD=STRICT_ANSI mode, the default is /PURE_CNAME.
    • In all other standard modes, the default is /NOPURE_CNAME.

    Inclusion of a <name.h> header instead of its <cname.h> counterpart (for example, <stdio.h> instead of <cstdio> ) results in inserting names defined in the header into both the std namespace and the global namespace. Effectively, this is the same as the inclusion of a <cname> header in the /NOPURE_CNAME mode.
    See Section 3.1 for more information.

4.1.6 Floating Point

This section describes floating-point behavior on I64 systems.

IEEE Now the Default

On OpenVMS I64 systems, /FLOAT=IEEE_FLOAT is the default floating-point representation. IEEE format data is assumed and IEEE floating-point instructions are used. There is no hardware support for floating-point representations other than IEEE, although you can specify the /FLOAT=D_FLOAT or /FLOAT=G_FLOAT compiler option.

These VAX floating-point formats are supported in the I64 compiler by generating run-time code that converts VAX floating-point formats to IEEE format to perform arithmetic operations, and then converts the IEEE result back to the appropriate VAX floating-point format. This imposes additional run-time overhead and some loss of accuracy compared to performing the operations in hardware on Alpha and VAX systems. The software support for the VAX formats is provided to meet an important functional compatibility requirement for certain applications that need to deal with on-disk binary floating-point data.

On I64 systems, the default for /IEEE_MODE is DENORM_RESULTS, which is a change from the default of /IEEE_MODE=FAST on Alpha systems. This means that by default, floating-point operations may silently generate values that print as Infinity or Nan (the industry-standard behavior), instead of issuing a fatal run-time error as they would when using VAX floating-point format or /IEEE_MODE=FAST. Also, the smallest-magnitude nonzero value in this mode is much smaller because results are allowed to enter the denormal range instead of being flushed to zero as soon as the value is too small to represent with normalization.

The conversion between VAX floating-point formats and IEEE formats on the Intel Itanium architecture is a transparent process that will not impact most applications. All you need to do is recompile your application. Because IEEE floating-point format is the default, unless your build explicitly specifies VAX floating-point format options, a simple rebuild for I64 systems will use the native IEEE formats directly. For the large class of programs that do not directly depend on the VAX formats for correct operation, this is the most desirable way to build for I64 systems.

When you compile an OpenVMS application that specifies an option to use VAX floating-point on an I64 system, the compiler automatically generates code for converting floating-point formats. Whenever the application performs a sequence of arithmetic operations, this code does the following:

  1. Converts VAX floating-point formats to either IEEE single or IEEE double floating-point formats.
  2. Performs arithmetic operations in IEEE floating-point arithmetic.
  3. Converts the resulting data from IEEE formats back to VAX formats.

Where no arithmetic operations are performed (VAX float fetches followed by stores), no conversion will occur. The code handles such situations as moves.

VAX floating-point formats have the same number of bits and precision as their equivalent IEEE floating-point formats. For most applications, the conversion process will be transparent and, therefore, a non-issue.

In a few cases, arithmetic calculations might have different results because of the following differences between VAX and IEEE formats:

  • Values of numbers represented
  • Rounding rules
  • Exception behavior

These differences might cause problems for applications that do any of the following:

  • Depend on exception behavior
  • Measure the limits of floating-point behaviors
  • Implement algorithms at maximal processor-specific accuracy
  • Perform low-level emulations of other floating-point processors
  • Use direct equality comparisons between floating-point values, instead of appropriately ranged comparisons (a practice that is extremely vulnerable to changes in compiler version or compiler options, as well as architecture)

You can test an application's behavior with IEEE floating-point values by first compiling it on an OpenVMS Alpha system using /FLOAT=IEEE_FLOAT/IEEE_MODE=DENORM.

If that produces acceptable results, then simply build the application on the OpenVMS I64 system using the same qualifier.

If you determine that simply recompiling with an /IEEE_MODE qualifier is not sufficient because your application depends on the binary representation of floating-point values, then first try building for your I64 system by specifying the VAX floating-point option that was in effect for your VAX or Alpha build. This causes the representation seen by your code and on disk to remain unchanged, with some additional runtime cost for the conversions generated by the compiler. If this is not an efficient approach for your application, you can convert VAX floating-point binary data in disk files to IEEE floating-point formats before moving the application to an I64 system.

/IEEE_MODE Notes

On Alpha systems, the /IEEE_MODE qualifier generally has its greatest effect on the generated code of a compilation. When calls are made between functions compiled with different /IEEE_MODE qualifiers, each function produces the /IEEE_MODE behavior with which it was compiled.

On I64 systems, the /IEEE_MODE qualifier primarily affects only the setting of a hardware register at program startup. In general, the /IEEE_MODE behavior for a given function is controlled by the /IEEE_MODE option specified on the compilation that produced the main program: the startup code for the main program sets the hardware register according the command-line qualifiers used to compile the main program.

When applied to a compilation that does not contain a main program, the /IEEE_MODE qualifier does have some effect: it might affect the evaluation of floating-point constant expressions, and it is used to set the EXCEPTION_MODE used by the math library for calls from that compilation. But the qualifier has no effect on the exceptional behavior of floating-point calculations generated as inline code for that compilation. Therefore, if floating-point exceptional behavior is important to an application, all of its compilations, including the one containing the main program, should be compiled with the same /IEEE_MODE setting.

Even on Alpha systems, the particular setting of /IEEE_MODE=UNDERFLOW_TO_ZERO has the following characteristic: its primary effect requires the setting of a runtime status register, and so it needs to be specified on the compilation containing the main program in order to be effective in other compilations.

More Information

For more information on I64 floating-point behavior, see the white paper OpenVMS floating-point arithmetic on the Intel Itanium architecture at http://www.hp.com/products1/evolution/alpha_retaintrust/download/i64-floating-pt-wp.pdf .

4.1.7 Intrinsics and Builtins

The C++ built-in functions available on OpenVMS Alpha systems are also available on I64 systems, with some differences. Section C.2 documents these differences and describes the built-in functions that are specific to I64 systems.

4.1.8 ELF

On OpenVMS Alpha systems, the C++ compiler uses a proprietary object format specific to OpenVMS.

On OpenVMS I64 systems, the compiler generates ELF objects. ELF is an industry standard object format used on many UNIX platforms, including Linux. This change should be transparent to most users; it is primarily of interest to compiler and tools developers. The greatest benefit of this change is that it should make it easier to create development tools that work on OpenVMS and other platforms.

Extensions to ELF have been used as needed to provide functionality unique to OpenVMS. See the Porting Applications from HP OpenVMS Alpha to HP OpenVMS Industry Standard 64 for Integrity Servers for more information on ELF.

COMDATS/Group Sections

One feature that ELF provides that is new to OpenVMS is the COMDAT section group---a group of sections in an object file that can be duplicated in one or more other object files. The linker is expected to keep one group and ignore all others. The benefit of this feature is that it permits compilers to generate definitions for symbols for things used in multiple objects without having to worry about creating a single definition in one place. The most notable uses for this feature are templates and inline functions.

New ELF Type for Weak Symbols

A new Executable and Linkable Format (ELF) type was generated to distinguish between the two types of weak symbol definitions.

For modules with ABI versions equal to 2 (the most common version used by compilers):

  • Type STB_WEAK represents the UNIX-style weak symbol (formerly, the OpenVMS-style weak symbol definition for ABI Version 1 ELF format).
  • Type STB_VMS_WEAK represents the OpenVMS-style of weak symbol definition.

The Librarian supports both the ELF ABI versions 1 and 2 of the object and image file formats within the same library.

4.1.9 Templates

This section describes template instantiation for I64 systems.

Implemented using ELF COMDATS/Groups Sections

The Alpha C++ compiler had numerous models for instantiating templates. Each attempted to solve the issue of how to generate one and only one copy of each template. The use of ELF on OpenVMS I64 systems provided the compiler with the additional option of using COMDAT section groups. Since this technique is superior to all the models supported on Alpha, this is the only model supported on I64 systems.

In this model, templates are instantiated in a COMDAT section group inside every object module that uses them. This is very similar to the /TEMPLATE=LOCAL on Alpha systems, except that when the objects are linked together, the linker removes the duplicate copies. The primary advantage of this technique over /TEMPLATE=LOCAL and /TEMPLATE=IMPLICIT_LOCAL is the reduction in image size.

A secondary advantage is the elimination of distinct data for each template. For example, if a template maintained a list of elements it created, each module would have a separate copy of the list. This behavior does not conform to the standard. If you are currently using /TEMPLATE=LOCAL or /TEMPLATE=IMPLICIT_LOCAL, you will likely experience no difficulty from this change.

Not in Repository

The most visible difference that results from this new instantiation model occurs in models that instantiate templates into the repository (/TEMPLATE=AUTOMATIC|ALL_REPOSITORY|USED_REPOSITORY).

With the new model, no repository is needed. Build procedures that use CXXLINK will work transparently. Builds that attempt to manipulate objects in the repository will fail and will need to be changed. In most cases, the reason for manipulating the repository directly has been eliminated with the new template instantiation model.

Also see Chapter 5.

4.1.10 Exceptions and Condition Handlers

The command-line option /EXCEPTIONS=NOCLEANUP is not implemented. As a result, you might see destructors being called during cleanup in code previously compiled with this option.

Exception specifications are not implemented. Exception specifications on routine declarations and definitions are accepted syntactically, but their run-time behavior has not yet been implemented.

4.1.10.1 Stack unwinding

According to the C++ Standard, an implementation may or may not unwind the stack before calling terminate when no matching handler is found for a thrown exception. On I64 systems, the implementation unwinds the stack. On Alpha systems, it does not.

Consider the following program:


      #include <exception> 
      #include <cstdio> 
      #include <cstdlib> 
 
       class C { 
       public: 
         C() { std::printf("Created\n"); } 
         ~C() { std::printf("Destroyed\n"); } 
 
       }; 
 
       void announce1() { 
         std::printf("In terminate\n"); 
         exit(0); 
       } 
 
       int main() { 
         C c; 
         std::set_terminate(announce1); 
         throw 5; 
 
         return 0; 
       } 

For the above program, the output on OpenVMS Alpha and I64 systems is:


   Alpha:            I64: 
 
   Created           Created 
   In terminate      Destroyed 
                     In terminate 

4.1.10.2 Exceptions Not Caught

The compiler assumes that the only two ways an exception can be propagated into a function are:

  • From a throw expression, or
  • From a routine call that itself can throw an exception.

As a result of this assumption, some exceptions such as those thrown from a signal handler will not be caught.

4.1.10.3 terminate() Incorrectly Called

The C++ I64 compiler incorrectly calls terminate() when, during unwinding, the destruction of an object results in an exception, even if this exception is caught within the destructor.

For example, consider the following program:


extern "C" int printf(const char *,...); 
 
struct killit { 
  killit () {} 
  ~killit () { 
    try { 
      throw 11; 
    } catch (int i) { 
      printf("caught %d\n", i); 
    } 
  } 
}; 
 
int main () { 
  try { 
 killit local; 
    throw 33; 
  } catch (const int &i) { 
    printf("caught int: %d\n", i); 
  } 
 
  return 0; 
} 

The expected output for the above example is:


caught 11 
caught int: 33 

But the executable produced by the C++ I64 compiler calls terminate() .

In cases where the expression to be thrown has been evaluated, but before the exception can be caught: if a called user function such as a copy constructor exits through an uncaught exception, then the compiler incorrectly attempts to match this latter exception object type to the handlers in enclosing try blocks in succession, instead of calling terminate() .

Further, the function uncaught_exception returns FALSE while in the called user function described above.

For example, consider the following program:


extern "C" int printf(const char *,...); 
extern "C" int exit(int); 
#include <exception> 
 
void announce () { 
    printf("Terminated!\n"); 
    exit(0); 
} 
 
class Y { 
  public: 
    Y () { printf ("construct Y\n"); } 
    Y(Y &rhs) { 
      printf ("copy Y\n"); 
      printf ("uncaught_exception = %s\n", std::uncaught_exception() ? 
                                           "TRUE" : "FALSE"); 
      throw 20; 
    } 
    ~Y () { printf ("destruct Y\n"); } 
}; 
   
void cxx_func () { 
    Y OBJ2; 
printf ("In cxx_func\n"); 
    try { 
        throw OBJ2; 
    } catch (const Y &) { 
        printf("Caught Y &\n"); 
    } catch (int i) { 
        printf("Caught %d\n", i); 
    } 
    printf ("leaving cxx_func\n"); 
} 
 
main () { 
    std::set_terminate(announce); 
    cxx_func(); 
    printf ("Leaving main\n"); 
} 

The expected output in the above example is:


construct Y 
In cxx_func 
copy Y 
uncaught_exception = TRUE 
Terminated! 

But the executable produced by the C++ I64 compiler outputs:


construct Y 
In cxx_func 
copy Y 
uncaught_exception = FALSE 
Caught 20 
leaving cxx_func 
destruct Y 
Leaving main 

The C++ I64 compiler also incorrectly calls terminate() when a destructor invoked during stack unwinding exits with an exception that violates its own exception specification, instead of calling unexpected() .

Consider the following program:


#include <exception> 
 
extern "C" void exit(int); 
extern "C" int printf(const char *,...); 
 
void announce2 () { 
    printf("announce2: Unexpected!\n"); 
    exit(0); 
} 
 
void announce1 () { 
    printf("announce1: Terminated!\n"); 
    exit(0); 
} 
 
class C { 
public: 
   C() { printf("C()\n"); } 
  ~C() throw() { std::set_unexpected(announce2); printf("~C()\n"); throw 3; } 
}; 
 
void foo() { 
    C c; 
    printf("throwing ...\n"); 
    throw 5; 
} 
 
main() { 
    std::set_terminate(announce1); 
    foo(); 
} 

In the above example, the expected output is:


C() 
throwing ... 
~C() 
announce2: Unexpected! 

But the executable produced by the C++ I64 compiler outputs:


C() 
throwing ... 
~C() 
announce1: Terminated! 

4.1.10.4 Problem in unexpected() Behavior

When a user-defined unexpected() routine throws or rethrows an exception, the compiler incorrectly checks the exception specification of the caller of the routine instead of that of the routine itself, which did not allow the exception in its exception specification.

Consider the following program:


#include <exception> 
#include <cstdlib> 
 
extern "C" int printf(const char *, ...); 
 
void my_unex() { 
  printf("In my unex\n"); 
  throw; 
} 
 
void my_term() { 
  printf("In my term\n"); 
  std::exit(0); 
} 
 
void foo() throw() {  // spec not checked with second rethrow 
  printf("In foo\n"); 
  throw 7; 
} 
 
void bar() throw(int) {  // this spec checked with second rethrow 
printf("In bar\n"); 
  foo(); 
} 
 
void foo2() throw(std::bad_exception) {  // spec not checked with first rethrow 
    printf("In foo2\n"); 
  throw 5; 
} 
 
int main() { 
  std::set_unexpected(my_unex); 
  std::set_terminate(my_term); 
  try { 
    foo2(); 
  } catch (int i) { 
    printf("Caught %d\n", i); 
} catch (std::bad_exception &) { 
    printf("Caught bad_exception\n"); 
  } 
 
  try { 
    bar(); 
  } catch (int i) { 
    printf("Caught %d\n", i); 
  } catch (...) { 
    printf("Caught ...\n"); 
  } 
  return 0; 
} 

In the above example, expected output is:


In foo2 
In my unex 
Caught bad_exception 
In bar 
In foo 
In my unex 
In my term 

But the compiler produces:


In foo2 
In my unex 
Caught 5 
In bar 
In foo 
In my unex 
Caught 7 

4.2 Library Changes

For I64 systems, the C++ standard library has been upgraded and organized as a shareable image. All applicable fixes and enhancements done in the C++ standard library for Alpha systems, have been applied to the C++ standard library for I64 systems.

The C++ class library on I64 systems is based on the same code as the C++ class library on Alpha systems. The major change in the C++ class library for I64 systems is the removal of the tasks and complex packages.

4.2.1 Library Reorganization

The standard library, language run-time support library, and class library have been reorganized for I64 systems.

4.2.1.1 Standard Library and Language Run-Time Support Library

On Alpha systems, the C++ standard library and language run-time support library is delivered in an object library, LIBCXXSTD.OLB, shipped with the compiler kit.

On I64 systems, the C++ standard library and language run-time support library are delivered as separate system shareable images shipped with the base operating system. The names of the images are: CXXL$RWRTL.EXE and CXXL$LANGRTL.EXE, respectively. The images reside in the SYS$LIBRARY directory and are installed at system startup. The LIBCXXSTD.OLB object library does not exist on I64 systems.

4.2.1.2 Class Library

On Alpha systems, there are three class library shareable images: CXXL$011_SHR.EXE, CXXL$011_SHRTASK.EXE, and CXXL$011_TASK.EXE.

On I64 systems, the C++ class library continues to ship as a system shareable image. Because the tasks and complex packages have been removed, there is only one class library image: CXXL$011_SHR.EXE.

4.2.2 Language Run-Time Support Library

The language run-time support library no longer validates if a negative value has been specified in a call to operator new . Instead, the value is treated as an unsigned value, and an attempt is made to dynamically allocate the specified memory.

4.2.3 Class Library

The following class library changes have been made:

  • The tasks and complex packages have been removed. The recommended replacements are the pthreads routines and complex template class, respectively, from the C++ standard library.
  • In the String class, the char*() operator, which converts String to a pointer to char , has been removed. The String class has a const char*() operator, which can be used instead of the removed one.

4.2.4 Standard Library

This section describes changes to the C++ standard library.

4.2.4.1 Changes

There are two major changes in the C++ standard library for I64 systems as compared with the standard library for Alpha systems:

  • The C++ standard library has been upgraded from Version 2.0 of the Rogue Wave C++ Standard Library to Version 3.0.
  • The C++ standard library is delivered with the operating system as the installed system shareable image SYS$SHARE:CXXL$RWRTL.EXE, and also in STARLET.OLB in the object form for linking /NOSYSSHARE. On I64 systems, there is no LIBCXXSTD.OLB, which is the object library where the C++ standard library for OpenVMS Alpha resides.

Additional standard library changes, known issues, and platform differences are noted in the following sections.

4.2.4.2 Library Headers

While the change in the library distribution model should be transparent to customers (except that application images are much smaller on I64 systems), users on I64 systems may find that the new C++ Standard Library is much less forgiving in terms of including all necessary library headers than the old Standard Library.

For example, the following program compiles cleanly on OpenVMS Alpha systems despite the fact that it does not include the <iostream> header necessary for the std::cout object:


#ifndef __USE_STD_IOSTREAM 
#define __USE_STD_IOSTREAM 
#endif 
#include <fstream> 
 
using namespace std; 
 
main() { 
  cout << "hello, world"; 
} 

However, on OpenVMS I64 systems, compilation fails with the following error:


%CXX-E-UNDECLARED, identifier "cout" is undefined 

It is nearly impossible to describe all combinations of library constructs and header files that would compile cleanly on Alpha systems and yet fail to compile on I64 systems because a library header required by the C++ standard for a particular construct has not been included. If a program that used to compile cleanly on an Alpha system fails to compile on an I64 system, it is always a good idea to check that all necessary library headers are included.

4.2.4.3 Internal Library Headers and Macros

A program that includes internal RW stdlib V2.0 library headers, like <stddefs> or <stdcomp> , or that uses internal library macros _RW_*, will have to be modified because the new C++ standard library does not necessarily have the same internal headers or use the same internal macros as the old one.

4.2.4.4 Known Issues and Restrictions

The following are known issues with C++ for OpenVMS I64 systems:

  • The C++ Standard Library IOStreams expect floating-point values in the IEEE format, which is the default floating-point format on I64 systems. Using the Standard Library IOStreams for processing floating-point values in a format other than IEEE (for example, in a program compiled with the /FLOAT=G_FLOAT or /FLOAT=D_FLOAT qualifier) is not supported. The C++ class library does not have this restriction.

4.2.4.5 Differences Between Alpha and I64 Systems

The following are differences between the I64 and Alpha standard libraries:

  • On OpenVMS Alpha systems, the following constructors for the C++ standard library classes strstream and ostrstream initialize ptr[count-1] with a null byte:


      strstream(char *ptr, streamsize count, 
                ios_base::openmode mode = ios_base::in | ios_base::out); 
     
      ostrstream(char *ptr, streamsize count, 
                 ios_base::openmode mode = ios_base::out); 
    

    This initialization is not required by the C++ standard, and on I64 systems the C++ standard library does not do it.
  • On I64 systems, map and multimap containers require the standard-conformant form of allocator class: allocator<pair<const Key, T> >.
    For example, on Alpha systems, it is possible to declare an object of class multimap as the following, with the second template argument of allocator class omitted:


    multimap<string, int, less<string>, allocator<string> > x; 
    

    But for I64 systems, this must be changed to:


    multimap<string, int, less<string>, allocator<pair<const string, int> > > x; 
    
  • On I64 systems, the exception.what() function reports the module name, and the message text might be different.
    For example, an output on Alpha systems:


    Got an exception: string index out of range in function: 
    basic_string:::replace(size_t,size_t,size_t,char) position: 100 is 
    greater than length: 0 
    

    An output on I64 systems:


    Got an exception: CSRC:[STDIPF_INCLUDE]STRING.CC;:416: 
    basic_string::replace(size_type, size_type, size_type, value_type): 
    argument value 100 out of range [0, 0) 
    
  • On I64 systems, iostreams extraction operators truncate out-of-range integer values to the maximum possible value for a given type, and set the failbit for the stream.
    For example, consider the following program:


    #ifndef __USE_STD_IOSTREAM 
    #define __USE_STD_IOSTREAM 
    #endif 
     
    #include <strstream> 
    #include <iostream> 
     
    using namespace std; 
     
    main() { 
      istrstream is("32768"); // SHRT_MAX is 32767 
      short s; 
      is >> s; 
      cout << is.fail() << endl; 
      cout << s << endl; 
    } 
    

    On Alpha systems, this program gives:


    0 
    -32768 
    

    On I64 systems, it gives:


    1 
    32767 
    

    Note that on I64 systems, the failbit for the stream is set.
    According to the C++ Standard, Section 22.2.2.1 - Template class num_get [lib.locale.num.get], an input that would have caused scanf to report an input failure should result in setting ios_base::failbit to err. Since on OpenVMS, scanf reports an input failure in this case (this is an undefined behavior from the point of view of the C standard), the behavior of the C++ standard library on I64 systems is standard-compliant.
  • On Alpha systems, the find template function is implemented using operator!= . On I64 systems, this function is implemented using operator== , which according to the C++ standard is the operator the find function should be using.
    Consequently, if no conversion from *InputIterator to T exists, on Alpha systems the following function can be instantiated only if operator!=(*InputIterator,T) exists:


    find(InputIterator first, InputIterator last, const T& value) 
    

    On I64 systems, however, the function can be instantiated only if operator==(*InputIterator,T) exists.
    The following program illustrates the difference. If you comment out the line bool operator!=(S, int); , the program does not compile on Alpha systems. If you comment out the line bool operator==(S, int); , the program does not compile on I64 systems. The behavior on I64 systems is the standard-conformant behavior.


    include <algorithm> 
    #include <vector> 
     
    struct S { 
      int i; 
    }; 
     
    bool operator!=(S, int); 
    bool operator==(S, int); 
     
    void foo() { 
      std::vector<S> v; 
      std::find(v.begin(), v.end(), 0); 
    } 
    
  • On I64 systems, an attempt to write into a stream opened for read (ios::in), causes the stream badbit bit to be set.
    On both Alpha and IPF systems, nothing is written into a stream opened for read. However, on Alpha systems, the stream badbit bit is not set.
    The C++ standard does not provide explicit guidance about what to do in this case. However, the behavior on I64 systems is more reasonable---at least there is an indication that something was wrong.
  • On I64 systems, reverse_iterator cannot be instantiated on vector<bool>::iterator type.
    For example, the following program, which compiles cleanly on Alpha systems, does not compile on I64 systems:


    #include <vector> 
     
    typedef std::reverse_iterator<std::vector<bool>::iterator> ri; 
     
    main() 
    { 
    ri::pointer (ri::*foo)() const = &ri::operator->; 
    } 
    

    A recently adopted resolution for the library issue 120 has made this construct invalid. See http://std.dkuug.dk/JTC1/SC22/WG21/docs/lwg-active.html#120 for more details.
  • On I64 systems, for a random access iterator, operator-(const random_access_iterator&) returning difference_type must be const .
    For example, the following program compiles cleanly on Alpha systems. However, on I64 systems it compiles only if // const is uncommented.


    #include <algorithm> 
     
    template <class T> class randomaccessiterator { 
     
    public: 
     
         typedef T value_type; 
         typedef int difference_type; 
         typedef T* pointer; 
         typedef T& reference; 
         typedef std::random_access_iterator_tag iterator_category; 
     
         bool operator==(const randomaccessiterator&); 
         bool operator!=(const randomaccessiterator&); 
         T& operator*() const; 
         T* operator->(); 
     
         randomaccessiterator& operator++(); 
         const randomaccessiterator& operator++(difference_type); 
         randomaccessiterator& operator--(); 
         const randomaccessiterator& operator--(difference_type); 
         randomaccessiterator& operator+=(difference_type); 
         randomaccessiterator& operator+(difference_type); 
         randomaccessiterator& operator-=(difference_type); 
         randomaccessiterator& operator-(difference_type); 
         difference_type operator-(const randomaccessiterator&); // const; 
    }; 
     
    struct S {}; 
    typedef randomaccessiterator<S> Iterator; 
    typedef bool (*Predicate)(Iterator::value_type); 
    template Iterator std::stable_partition<Iterator, Predicate>(Iterator, 
    Iterator, Predicate); 
    

    Table 76 in the C++ standard specifies the requirements for a random access iterator. It says the expression b - a must be valid, where a and b denote values of X, the random access iterator. It is not completely clear from the standard whether values of X also imply const values of X, but if the answer is yes, the behavior on I64 systems is correct.
  • On I64 systems, an attempt to call the strstream.seekg(0) function for an empty stream (the one whose 'next' pointer is NULL) causes the stream failbit to be set.
    This is a standard-compliant behavior. Notice that after the failbit is set for the stream, the strstream.str() function returns a NULL pointer.
  • On I64 systems, after a call to string.resize(newsize), string.capacity() does not necessarily returns newsize.
    While on Alpha systems the string.capacity() function returns newsize, this is not required by the C++ standard. A program relying on Alpha behavior should be modified to call the string.size() function instead.
  • On I64 systems, there is no overload of basic_string class for type bool .
    Version v3.0 of the Rogue Wave C++ standard library does not have this problematic nonstandard overload. For OpenVMS Alpha, it has been recently removed from the library.
  • On I64 systems, class std::fpos<std::mbstate_t> does not have the nonstandard member function offset(). You can use fpos::operator streamoff() instead. For example:


    #ifndef __USE_STD_IOSTREAM 
    #define __USE_STD_IOSTREAM 
    #endif 
     
    #include <sstream> 
     
    using namespace std; 
     
    void foo() { 
      istringstream in("hello, world"); 
      streamoff offset; 
      offset = in.tellg().offset();    // Alpha only 
      offset = streamoff(in.tellg());  // either Alpha or IPF 
    } 
    
  • On OpenVMS Alpha systems, in the default built-in C locale, the monetary facets use values typically found in the en_US locale (English in the United States). For example, on Alpha the default national currency string is "$". On I64 systems, in any locale, including the C locale, the monetary facets use values defined by the locale.
    Consider the following sample program:


    #ifndef __USE_STD_IOSTREAM 
    #define __USE_STD_IOSTREAM 
    #endif 
     
    #include <iostream> 
    #include <locale> 
    #include <stdexcept> 
    #include <stdlib.h> 
     
    #if defined(__osf__) || defined(__vms) 
    #  define UK_LOCALE "en_GB.ISO8859-1" 
    #elif defined(__linux) 
    #  define UK_LOCALE "en_GB" 
    #else 
    #  error unknown platform 
    #endif 
     
    using namespace std; 
     
    void outputSym(ostream& os) { 
      locale loc = os.getloc(); 
      const moneypunct<char,false>& mpunct = 
          use_facet<moneypunct<char,false> >(loc); 
      os << "currency symbol is: " << mpunct.curr_symbol() << endl; 
    } 
    

    This program prints two lines: the national currency symbol in the C locale and the national currency symbol in the en_GB locale (English in Great Britain).


       currency symbol is: $ 
     
       currency symbol is: £
    

    On I64 systems, the output is:


       currency symbol is: 
     
       currency symbol is: £
    
  • Consider a program using the C++ Standard Library IOStreams, like x.cxx below, that writes to cout , but not to cerr or clog :


    x.cxx 
    ----- 
    #ifndef __USE_STD_IOSTREAM 
    #define __USE_STD_IOSTREAM 
    #endif 
    #include <iostream> 
     
    main() { 
      std::cout << "hello, world" << std::endl; 
    } 
    

    On OpenVMS Alpha systems, if such a program is invoked with SYS$OUTPUT redirected to a file and SYS$ERROR defined as SYS$OUTPUT, a single version of the output file is created.
    On I64 systems, by default, two versions of the file are created: one for SYS$OUTPUT and another for SYS$ERROR. To get Alpha behavior on an I64 system, define logical name DECC$COMMON_STDERR_STDOUT to ENABLE. The following command file shows the definition:


    x.com 
    ----- 
    $ if f$search("x.dat") .nes. "" then delete x.dat;* 
    $ define/user sys$output x.dat 
    $ define/user sys$error sys$output 
    $ if f$getsy("arch_name") .eqs. "IA64" then - 
        define/user decc$common_stderr_stdout enable 
    $ run x.exe 
    

4.3 CXXLINK Changes

Because of changes in the architecture on I64 systems, CXXLINK plays a much smaller role. Its only remaining purpose is to provide human readable (demangled) names for mangled C++ names in diagnostics generated by the linker.

Specific changes are:

  • There is no LIBCXXSTD.OLB
    On I64 systems, there is no LIBCXXSTD.OLB, which is the object library where the C++ standard library for OpenVMS Alpha resides. See Section 4.2.4 for more information.
  • The library is reorganized
    The C++ libraries have been reorganized and incorporated into the base system. CXXLINK no longer needs to specify any C++ libraries when invoking the system linker. See Section 4.2 for more information.
  • There are no templates in a repository
    With the new template instantiation model, objects are no longer placed in a repository. Therefore, CXXLINK no longer needs to look at the repositories for templates. See Section 4.1.9 for more information.

4.4 Installation

HP C++ is installed using PCSI for OpenVMS I64 systems.

To install HP C++ for OpenVMS I64 systems, set the default directory to a writeable directory to allow the IVP to succeed. Then run the PRODUCT INSTALL command, pointing to the kit location. For example:


$ SET DEFAULT SYS$MANAGER 
$ PRODUCT INSTALL CXX/SOURCE=node::device:[kit_dir] 

After installation, the C++ release notes will be available at:

SYS$HELP:CXX.RELEASE_NOTES

SYS$HELP:CXX_RELEASE_NOTES.PS

Here is a sample installation log:


$ PRODUCT INSTALL CXX/SOURCE=NODE1$::DEV1$:[I64_CPP_KIT] 
 
The following product has been selected: 
    HP I64VMS CXX T7.0-9                   Layered Product [Installed] 
 
Do you want to continue? [YES] 
 
Configuration phase starting ... 
 
You will be asked to choose options, if any, for each selected product and for 
any products that may be installed to satisfy software dependency requirements. 
 
HP I64VMS CXX T7.0-9: HP C++ for OpenVMS Industry Standard 
 
    Copyright 2004 Hewlett-Packard Development Company, L.P. 
 
    This software product is sold by Hewlett-Packard Company 
 
    PAKs used: CXX or CXX-USER 
 
Do you want the defaults for all options? [YES] 
 
    Copyright 2004 Hewlett-Packard Development Company, L.P. 
 
      HP, the HP logo, Alpha and OpenVMS are trademarks of 
      Hewlett-Packard Development Company, L.P. in the U.S. and/or 
      other countries. 
 
      Confidential computer software. Valid license from HP 
      required for possession, use or copying.  Consistent with 
      FAR 12.211 and 12.212, Commercial Computer Software, Computer 
      Software Documentation, and Technical Data for Commercial 
      Items are licensed to the U.S. Government under vendor's 
      standard commercial license. 
 
Do you want to review the options? [NO] 
 
Execution phase starting ... 
 
The following product will be installed to destination: 
    HP I64VMS CXX T7.0-9                   DISK$ICXXSYS:[VMS$COMMON.] 
 
Portion done: 0%...90%...100% 
 
The following product has been installed: 
    HP I64VMS CXX T7.0-9                   Layered Product 
 
%PCSI-I-IVPEXECUTE, executing test procedure for HP I64VMS CXX T7.0-9 ... 
%PCSI-I-IVPSUCCESS, test procedure completed successfully 
 
HP I64VMS CXX T7.0-9: HP C++ for OpenVMS Industry Standard 
 
The compiler is now available from the command line of newly created processes. 
 
      To enable access to the compiler from the command line of a currently 
      running process (such as this one), execute: 
      SET COMMAND/TABLE=SYS$COMMON:[SYSLIB]DCLTABLES 
 
  The release notes are located in the file SYS$HELP:CXX.RELEASE_NOTES 
  for the text form and SYS$HELP:CXX_RELEASE_NOTES.PS for the postscript form. 
$ 


Previous Next Contents Index