Compaq C++Using Compaq C++ for Tru64
UNIX and Linux Alpha

Chapter 4Porting to Compaq C++

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
-std arm
option. See The C++ Standard Library
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.

4.1 Compatibility with Other C++ Compilers

In default mode (
-std ansi
), the compiler implements most features of the International C++
Standard including:

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

-std ansi

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.

If you want to use ANSI mode but find that the compiler generates too
many diagnostics in that mode, you can use the
-msg_quiet
option with the
-std ansi
option. The
-msg_quiet
option relaxes error checking and suppresses or reduces the severity of many diagnostics. It also suppresses many warnings that are generated in ANSI mode but were not issued by Version 5.6. For information on message control options, see
Message Control Options
in Chapter 2
.

-std arm

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

If you usually want your compilations done in this mode and don't want
to specify
-std arm
on each cxx command, define environment variable
DEC_CXX
as follows:

setenv DEC_CXX "-std arm"

You can place a single vertical bar ("|") within the variable. All
arguments preceding the bar are evaluated before any explicit
command-line arguments; all arguments following the bar are evaluated
afterwards. In the absence of a vertical bar, all arguments are
evaluated before the explicit command-line arguments.

Specify
-v
to obtain the definition of
DEC_CXX
For example, assuming the definition of DEC_CXX above, the
cxx -v
command results in the following:

% cxx -v
$DEC_CXX contains: -std arm

To enhance compatibility with other C++ compilers, Compaq C++
supports options that direct the compiler to interpret the source
program according to certain rules followed by other implementations:

-std cfront

Specify this option if you want to compile programs developed using
cfront or a compiler based on cfront.

-std gnu

Use this option if you want to compile programs developed using the GNU
compiler. This option also defines the
__STD_GNU
macro. The following changes in behavior are provided for compatibility
with the GNU C++ compiler:

These options are enabled by default:

-alternative_tokens, -tlocal, and -no_implicit_include

Access control is not enforced for types defined inside a class.

Unrecognized character escape sequences in string literals produce
an informational instead of a warning message.

The
__inline
keyword is enabled and is equivalent to
inline
.

When overloading,
enum
types are treated as integral types.

The following known incompatibilities are not addressed in the
-std gnu
mode:

The compiler strictly enforces the requirement to define functions
before they are used. This requirement also applies to built-in
functions such as
strlen
.

-std ms

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

-std strict_ansi

Specify this option if you want the compiler to enforce the ANSI C++
standard strictly but permit some ANSI violations that should be errors
to be warnings.

-std strict_ansi_errors

Specify this option if you want strict_ansi and also
want errors to be issued for all ANSI violations.

With either
-std ms
or
-std cfront
you might also want to specify
-msg_quiet
to reduce the number of diagnostic messages generated. For details, see
Message Control Options
in Chapter 2
.

4.2 Compatibility With Version 5.n Compilers [Tru64]

This section provides information about differences between the current
compiler and Version 5.n compilers.

4.2.1 Compiler Version Options [Tru64]

This release provides the following compiler version options:

-newcxx

Invokes the Version 6.3 compiler. This is the default.

-oldcxx

Invokes a bug fix update to the Version 5.7 compiler.

The
-oldcxx
option is provided for cases where the Version 6.n compiler
requires excessive source changes or for problems in using that
compiler. If extensive source changes are required to correct errors,
try using the
-std arm
option. For excessive warnings, try the
-msg_quiet
option.

If you want
-oldcxx
to be the default, define the
DEC_CXX
environment variable as follows:

4.2.2 Language Differences [Tru64]

Be aware of the following language differences between the current
compiler and Version 5.n compilers:

The most important language differences result from the
implementation of the International C++ Standard in Version
6.n. If you want to compile existing source code with minimal
source changes, specify the
-std arm
option.

Because the current compiler performs more error checking than
previous versions, it generates significantly more diagnostic messages.
However, you can use the
-msg_quiet
option to relax error checking and reduce the severity of many diagnostics. See Compaq C++ Implementation
. With some option combinations, you might see unwanted diagnostics
from system header files. If so, you might obtain better results if you
protect your system header files using the script provided in
/usr/lib/cmplrs/cxx/protect_system_headers.sh.
For more information, see Protecting System Header Files
.

The current compiler fixes several class member access bugs in
previous versions. Some illegal programs that compiled cleanly with
previous versions require modification to compile with the current
version.

The following keywords, introduced with the International C++
Standard, are always keywords in all compiler modes:

In the current version,
bool
is a built in type. In previous versions, it is user defined, typically
as
int
in system header files. Mangling therefore differs between the current
and previous versions. In the current version, the size of
bool
is 1. In previous versions,
bool
is user defined, typically as
int
with a size of 4. In the current version, the size of a boolean
expression
(sizeof(a && b))
is 1. In previous versions, the size is 4, independent of the size of
bool
.

The current version does not cause pragmas to become effective
within function bodies when scanning template definitions.

The current version does not permit dropping qualifiers on pointer
assignments. For example, the following is not permitted:

volatile int *vptr; int *ptr=vptr;

The current version does not allow the "virtual" storage
class modifier to be used with member function definitions outside a
class.

The current version does not allow declaration of pointers to
members of type void. For example, the following is not allowed:

typedef void Z::* any_ptom;

4.2.3 Implementation Differences [Tru64]

Users should be aware of the following implementation differences
between the current and previous versions of the compiler:

The automatic template instantiation model has been redesigned for the current version. See Using Templates
.

The current version does not support the
-show statistics
option implemented in Version 5.7.

The current version drops qualifiers on parameters when determining
the function type, as dictated by the International C++ 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.

The current and previous versions differ in interpreting undefined
behavior, as when incrementing takes effect in this example:

f(i++, i++);

The current version cannot handle a
#pragma define_template
that spans multiple lines without the backslash ( \ ) delimiter.
Version 5.6 can handle this without problems.

The current version displays
#line number
in
-E
output. The previous version displays
#number
.

After encountering an illegal multibyte character sequence, the
current version issues a warning diagnostic and continues processing.
The previous version issues an error and stops processing.

4.3.2 Member Access

Unlike some older C++ implementations, Compaq 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.

4.3.3 Base Class Initializers

Unlike some older C++ implementations, Compaq 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:

4.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. On CompaqTru64 UNIX and Linux Alpha systems, the compiler
does not support the declaration anachronism shown in The C++ Programming Language, 3rd Edition.

The compiler does not issue any messages during compilation; however,
when you attempt to link a program containing this code, the linker
issues a message similar to the following:

ld:
Error: Undefined:
i__1C

4.5 Functions and Function Declaration Considerations

Compaq C++ requires the use of function definitions as described in
The C++ Programming Language, 3rd Edition. For examples of outdated syntax not allowed in
Compaq 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.

Similarly, the declaration
int f(i,j)
causes an error even when the declaration is defined with the
"C"
linkage specification, because the linkage specification has no effect
on the semantics of the declaration.

4.6 Using Pointers

This section explains how to use pointers effectively in Compaq C++.

4.6.1 Pointer Conversions

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

4.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 Compaq C++. For more
information on the illegality of casting bound pointers, see
The C++ Programming Language, 3rd Edition.

4.6.3 Constants in Function Returns

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

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.

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

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.

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

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.

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

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

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

4.11 Preprocessing

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

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

4.13 Size-of-Array Argument to delete Operator

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

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

4.15 Missing Parenthesis Error Message

Situations occur in which a simple typographical error generates a
missing parenthesis error message. In the following example, the class
name
CaseSensitive
is incorrectly specified as
Casesensitive
in the constructor declaration:

class CaseSensitive {
void Test( const Casesensitive &foo );
};

As the compiler parses the argument declaration list:

It interprets
const
as a type specifier.

It interprets
Casesensitive
as a different indentifier.

Among the next legal tokens are the equal sign, comma, and closing
parenthesis. Upon finding an ampersand, the compiler expects a closing
parenthesis. With all other possibilities exhausted, the compiler has
what appears to be a legal argument declaration list, after which the
closing parenthesis is the only allowable token. The compiler expected
one thing but encountered something else. Often, inserting newline
characters can isolate the offending token.

4.16 Link Using cxx

Use the
cxx
command, not the
ld
command, to build a binary; otherwise, the run-time startup and other
crucial code will not build properly. Some symptoms of linking
incorrectly are

Segmentation faults (signal
SEGV
) occur while running your program

Undefined symbols

Static constructors not being executed

4.17 Source File Extensions

Compaq C++ automatically treats files with a
.c
extension as C language source files and passes the files to the
cc
command. For Compaq C++ to compile them, your files must have one of
the following extensions:

.cxx .CXX
.cpp .CPP
.cc .CC
.C .C++

You also can use the
-x
option to direct the compiler to ignore file-name extensions and treat
all named files, other than those with an
.a
or
.o
extension, as C++ source files.

4.18 Incrementing Enumerations

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

4.19 Scope of Variables Declared on a for Statement

If the for-init-statement is a declaration, the scope of the name(s)
declared extends to the end of the for-statement, as shown in the
following example:

int i=5;
void f()
{
for (int i=0;i<10;i++);
printf("%d\n",i);
}

When compiled
-std ansi
,
strict_ansi
, or
strict_ansi_errors
, the compiler produces the results expected by the International C++
Standard. In all other modes, the compiler produces the results
expected by The Annotated C++ Reference Manual; that is, the scope of the names declared
extends to the end of the enclosing scope.

4.20 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 Alpha systems should be declared as
int
(not
long
). Even better would be to declare them as
int32
, which is a macro you define to be
int
.

Variables that should be 32 bits in size on a 32-bit system and 64
bits in size on a 64-bit Alpha system should be declared as
long
. Even better would be to declare them as
long-int
, which is a macro you define to be
long
.

Check any variables in your code that are declared
long
. If the variable must be 32 bits in size, you must change its type to
int
.

Variables declared as
int
should not be used to hold an address;
sizeof (int)
does not equal
sizeof (char *)
on Alpha systems.

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;

Using a 0 where you should use
NULL
generates a 32-bit constant. On Alpha systems, this could yield 0 in
the low 32 bits and useless data in the high 32 bits when passed into a
function that accepts a variable number of arguments. Using
NULL
from the
<stdio.h>
header file provides the correct value.

Assigning to a
char
is not atomic on Alpha processors before the EV56. You will obtain 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.