C++ Migration Guide

Chapter 1 Introduction

In this book, the C++ 4.0, 4.0.1, 4.1, and 4.2 compilers are referred to collectively as "C++ 4." To a large degree, C++ source code that compiled and ran under C++ 4 continues to work under the C++ 5.0 compiler, with a few exceptions that are due to changes in the C++ language definition. The C++ 5.0 compiler provides a compatibility mode (-compat=4) that allows nearly all of your C++ 4 code to continue to work unchanged.


Note -

C++ 5.0 object code compiled in standard mode is not compatible with C++ code from any earlier compiler. It is still possible to use self-contained libraries of older object code with the C++ 5.0 compiler. The details are covered in "Binary Compatibility Issues".


The C++ Language

C++ was first described in The C++ Programming Language (1986) by Bjarne Stroustrup, and later more formally in The Annotated C++ Reference Manual (the ARM) (1990), by Margaret Ellis and Bjarne Stroustrup. The Sun C++ 4 compiler versions were based primarily on the definition in the ARM, with additions from the then-emerging C++ standard. The additions selected for inclusion in C++ 4, and particularly in the C++ 4.2 compiler, were mainly those that did not cause source and binary incompatibility.

C++ is now the subject of an international standard, ISO/IEC 14882:1998 Programming Languages - C++. The C++ 5.0 compiler in standard mode implements nearly all of the language as specified in the standard. The README file that accompanies the current release describes any departures from requirements in the standard.

Some changes in the C++ language definition prevent compilation of old source code without minor changes. The most obvious example is that the entire C++ standard library is defined in namespace std. The traditional first C++ program


#include <iostream.h>
int main() { cout << "Hello, world!" << endl; }

no longer compiles under a strictly-conforming compiler because the standard name of the header is now <iostream> (without the .h), and the names cout and endl are in namespace std, not in the global namespace. The C++ 5.0 compiler, as an extension, provides a header <iostream.h> that allows that program to compile even in standard mode. Besides the source code changes required, such language changes create binary incompatibilities, and so were not introduced into the Sun C++ compiler prior to version 5.0.

Some newer C++ language features also required changes in the binary representation of programs. This subject is discussed in some detail in "Binary Compatibility Issues".

Compiler Modes of Operation

The C++ 5.0 compiler has two modes of operation, standard mode and compatibility mode.

Standard Mode

Standard mode implements most of the C++ International Standard, and has some source incompatibilities with the language accepted by C++ 4, as noted earlier.

More importantly, the C++ 5.0 compiler in standard mode uses an Application Binary Interface (ABI) different from that of C++ 4. Code generated by the compiler in standard mode is generally incompatible with, and cannot be linked with, code from the various C++ 4 compilers. This subject is discussed in more detail in "Binary Compatibility Issues".

You should update your code to compile in 5.0 standard mode, for several reasons:

Compatibility Mode

To provide a migration path from C++ 4 to C++ 5.0 standard mode, the C++ 5.0 compiler provides a compatibility mode. The compatibility mode is fully binary compatible and mostly source compatible with the C++ 4 compiler. (Compatible means upward compatible. Older source and binary code works with the new compiler, but you cannot depend on code intended for the new compiler working with an old compiler.) Compatibility mode is not binary compatible with standard mode. Compatibility mode is available for Intel and SPARC on Solaris 2.5.1, 2.6, and Solaris 7, but not for SPARC V9 (64-bit Solaris 7).

Reasons to use compatibility mode:

Binary Compatibility Issues

An Application Binary Interface, or ABI, defines the machine-level characteristics of the object program produced by a compiler. It includes the sizes and alignment requirements of basic types, the layout of structured or aggregate types, the way in which functions are called, the actual names of entities defined in a program, and many other features. Much of the C++ ABI for Solaris is the same as the basic Solaris ABI, which is the ABI for the C language.

Language Changes

C++ introduced many features (such as class member functions, overloaded functions and operators, type-safe linkage, exceptions, and templates) which did not correspond to anything in the ABI for C. Each major new version of C++ added language features that could not be implemented using the previous ABI. Necessary ABI changes have involved the way class objects are laid out, or the way in which some functions are called, and the way type-safe linkage ("name mangling") can be implemented.

The C++ 4.0 compiler implemented the language defined by the ARM. By the time the C++ 4.2 compiler was released, the C++ committee had introduced many new language features, some requiring a change in the ABI. Because it was certain that additional ABI changes would be required for as-yet unknown language additions or changes, Sun elected to implement only those new features that did not require a change to the ABI. The intent was to minimize the inconvenience of having to maintain correspondence of binary files compiled with different compiler versions. Now that the C++ standard has been published, Sun has designed a new ABI that allows the full C++ language to be implemented. The C++ 5.0 compiler uses the new ABI by default.

One example of language changes affecting the ABI is the new names, signatures, and semantics of the new and delete free-store functions. Another is the new rule that a template function and non-template function with the same signature are nevertheless different functions. This rule required a change in "name mangling," that created a binary incompatibility with older compiled code. The introduction of type bool also created an ABI change, particularly regarding the interface to the standard library. Because the ABI needed to change, aspects of the old ABI that resulted in needlessly inefficient runtime code were improved.

Mixing Old and New Binaries

It is an overstatement to say that object files and libraries compiled by the 4.2 compiler cannot be linked with object files and libraries compiled by the 5.0 compiler. The statement is true whenever the files and libraries present a C++ interface.

Sometimes a library is coded in C++ for convenience, yet presents only a C interface to the outside world. Put simply, having a C interface means that a client cannot tell the program was written in C++. More specifically, having a C interface means that all of the following are true:

If a library meets the C-interface criteria, it can be used where ever a C library can be used. In particular, such libraries can be compiled with one version of the C++ compiler and linked with object files compiled with a different version.

However, if any of these conditions are violated, the files and libraries cannot be linked together. If an attempted link succeeds, which is doubtful, the program does not run correctly.

Conditional Expressions

The C++ standard introduced a change in the rules for conditional expressions. The difference shows up only in an expression like

e ? a : b = c

The critical issue is having an assignment following the colon when no grouping parentheses are present.

The 4.2 compiler used the original C++ rule and treats that expression as if you had written

(e ? a : b) = c

That is, the value of c will be assigned to either a or b depending on the value of e.

The 5.0 compiler in both compatibility and standard mode uses the new C++ rule. It treats that expression as if you had written

e ? a : (b = c)

That is, c will be assigned to b if and only if e is false.

Solution: Always use parentheses to indicate which meaning you intend. You can then be sure the code will have the same meaning when compiled by any compiler.

Function Pointers and void*

In C there is no implicit conversion between pointer-to-function and void*. The ARM added an implicit conversion between function pointers and void* "if the value would fit." C++ 4.2 implements that rule. The implicit conversion was later removed from C++, since it causes unexpected function overloading behavior, and because it reduces portability of code. In addition, there is no longer any conversion, even with a cast, between pointer-to-function and void*.

C++ 5.0, in both compatibility mode and standard mode, now issues a warning for implicit and explicit conversions between pointer-to-function and void*. In both modes it no longer recognizes such implicit conversions when resolving overloaded function calls. Such code that currently compiles with the 4.2 compiler generates an error (no matching function) with the 5.0 compiler. If you have code that depends on the implicit conversion for proper overload resolution, you need to add a cast. For example:


int g(int);
typedef void (*fptr)();
int f(void*);
int f(fptr);
void foo()
{
    f(g);          // This line has different behavior
}

With the 4.2 compiler, the marked line in the code example calls f(void*). With the 5.0 compiler, there is no match, and you get an error message. You can add an explicit cast, such as f((void*)g), but you will get a warning because the code is invalid. You should modify your code so that you do not need to convert between function pointers and void*. Such code has never been portable, even when this conversion was allowed.

C++ does not have a "universal function pointer" corresponding to void*. With C++ on all supported platforms, all function pointers have the same size and representation. You can therefore use any convenient function pointer type to hold the value of any function pointer. This solution is portable to many, but not all, platforms. As always, you must convert the pointer value back to its original type before attempting to call the function that is pointed to. See also "Pointers to extern "C" Functions".