DIGITAL C++
Using DIGITAL C++ for DIGITAL UNIX Systems


Previous Contents Index

2.3.18 File Inclusion

The #include directive inserts external text into the macro stream delivered to the DIGITAL C++ compiler. Programmers often use this directive to include global definitions for use with DIGITAL C++ functions and macros in the program stream.

The #include directive has the following search path semantics:

2.3.19 Nested Enums and Overloading

The C++ language allows programmers to give distinct functions the same name, and uses either overloading or class scope to differentiate the functions:


void f(int); 
void f(int *); 
class C {void f(int);}; 
class D {void f(int);}; 

Yet, linkers know nothing about overloaded parameter types or classes, and they complain if there is more than one definition of any external symbol. C++ compilers, including DIGITAL C++, solve this problem by assigning a unique mangled name (also called type safe linkage name) to every function. These unique mangled names allow the linker to tell the overloaded functions apart.

The compiler forms a mangled name, in part, by appending an encoding of the parameter types of the function to the function's name, and if the function is a member function, the function name is qualified by the names of the classes within which it is nested.

For example, for the function declarations at the beginning of this section, the compiler might generate the mangled names f__Xi, f__XPi, f__1CXi, and f__1DXi respectively. In these names, i means a parameter type was int, P means "pointer to", 1C means nested within class C, and 1D means nested within class D.

There is a flaw in the name mangling scheme used by DIGITAL C++ that can cause problems in uncommon cases. DIGITAL C++ fails to note in the encoding of an enum type in a mangled name whether the enum type was nested within a class. This can cause distinct overloaded functions to be assigned the same mangled name:


struct C1 {enum E {red, blue};}; 
struct C2 {enum E {red, blue};}; 
 
extern "C" int printf(const char *, ...); 
void f(C1::E x) {printf("f(C1::E)\n");} 
void f(C2::E x) {printf("f(C2::E)\n");} 
 
int main() 
{ 
    f(C1::red); 
    f(C2::red); 
} 

In the previous example, the two overloaded functions named f differ only in that one takes an argument of enum type C1::E and the other takes an argument of enum type C2::E. Since DIGITAL C++ fails to include the names of the classes containing the enum type in the mangled name, both functions have mangled names that indicate the argument type is just E. This causes both functions to receive the same mangled name.

In some cases, DIGITAL C++ detects this problem at compile-time and issues a message that both functions have the same type-safe linkage. In other cases, DIGITAL C++ issues no message, but the linker complains about duplicate symbol definitions.

If you encounter such problems, you can recompile using the
-distinguish_nested_enums command line switch. This causes DIGITAL C++ to include the name of class or classes that an enum is nested within when forming a mangled name. This eliminates cases where different functions receive the same mangled name.

Because the -distinguish_nested_enums command-line switch changes the external symbols the compiler produces, you can get undefined symbol messages from the linker if some modules are compiled with -distinguish_nested_enums and some are compiled without it. Because of this, -distinguish_nested_enums might make it difficult to link against old object files or libraries of code. If you compile your code with
-distinguish_nested_enums and try to link against a library that was compiled without the -distinguish_nested_enums command line switch, you will receive an undefined symbol message from the linker if you attempt to call a function from the library that takes an argument of a nested enum type. The mangled name of the function in the library will be different from the mangled name your code is using to call the function.

2.4 Message Control Options

DIGITAL C++ supports the following message control options. The options apply only to discretionary, warning, and informational messages. The tag variable is either a tag obtained from -msg_display_tag or a number obtained from -msg_display_number.

-msg_inform tag,...

Alter message(s) severity to informational.

-msg_warn tag,...

Alter message(s) severity to warning.

-msg_error tag,...

Alter message(s) severity to error

-msg_enable tag,...

Enable specific messages that normally would not be issued when using -msg_quiet. You can also use this option to enable messages disabled with -msg_disable.

-msg_disable tag,...

Disable message. This can be used for any nonerror message.

-msg_quiet

Be more like DIGITAL C++ Version 5.n error reporting. Fewer messages are issued using this option.

This is the default in arm mode (-std arm). All other modes default to -nomsg_quiet.

You can use the msg_enable option with this option to enable specific messages normally disabled using -msg_quiet.

2.5 Message Information Options

DIGITAL C++ supports the following message information options. Both are disabled by default.

Note

"D" (meaning discretionary) indicates that the severity of the message can be controlled from the command line. The message number can be used as the tag in the message control options described in Section 2.4. If "D" is not displayed with the message number, any attempt to control the message is ignored.

-msg_display_tag

A more descriptive tag is issued at the end of each message issued. "D" indicates the severity of the message can be controlled from the command line. The tag displayed can be used as the tag in the message control options described in
Section 2.4.

Example:


cxx -msg_display_tag t.cxx 
cxx: ... is nonstandard ("int" assumed) (D:nonstd_implicit_int) 
cxx -msg_disable nonstd_implicit_int  t.cxx 

Note that you can change the severity of a diagnostic message if the message is discretionary. For example, -msg_inform nonstd_implicit_int changes the severity to an informational. These options interact with -w0, -w1, and -w2.

-msg_display_number

The error number is displayed at the beginning of each message issued.

Example:


cxx -msg_display_number t.cxx 
cxx: Warning: t.cxx, line 1: #117-D non-void function "f" ... 
cxx -msg_disable 117 t.cxx 


Chapter 3
DIGITAL C++ Language Environment

This chapter describes the guidelines and procedures for customizing your language environment. It includes sections on changing your C header files to work with C++, using 32-bit pointers, organizing your C++ files, interfacing to other programming languages, and designing upwardly compatible C++ classes.

3.1 Using Existing C Header Files

C header files that already conform to ANSI C standards must be slightly modified for use by DIGITAL C++ programs. In particular, be sure to address the following issues:

The following sections provide details on how to properly modify your header files.

3.1.1 Providing C and C++ Linkage

To modify header files, use conditional compilation and the extern specifier.

When programming header files to be used for both C and C++ programs, use the following convention for predefined macros. The system header files also provide an example of correct usage of the predefined macros.


#if defined __cplusplus 
    /* If the functions in this header have C linkage, this 
     * will specify linkage for all C++ language compilers. 
     */ 
    extern "C" { 
#endif 
 
extern int func1(int); 
extern int func2(int); 
   .
   .
   .
#if defined __cplusplus 
    }   /* matches the linkage specification at the beginning. */ 
#endif 

See The C++ Programming Language, 3rd Edition for more information on linkage specifications.

3.1.2 Resolving C++ Keyword Conflicts

If your program uses any of the following C++ language keywords as identifiers, you must replace them with nonconflicting identifiers:
asm bool catch class
const_cast delete dynamic_cast explicit
export false friend inline
mutable new operator private
protected public reinterpret_cast static_cast
template this throw true
try typeid typename virtual
wchar_t      

3.1.3 Support for <stdarg.h> and <varargs.h> Header Files

DEC C has special built-in macros defined in the header files <stdarg.h> and <varargs.h>. These step through the argument list of a routine.

Programs that take the address of a parameter, and use pointer arithmetic to step through the argument list to obtain the value of other parameters, assume that all arguments reside on the stack and that arguments appear in increasing order. These assumptions are not valid for DIGITAL C++. Furthermore, the macros in <varargs.h> can be used only by C functions with old-style definitions that are not legal in C++. To reference variable-length argument lists, use the <stdarg.h> header file.

3.2 Using DIGITAL C++ with Other Languages

The following are suggestions regarding the use of DIGITAL C++ with other languages:

3.3 Linkage to Non-C++ Code and Data

With linkage specifications, you can both import code and data written in other languages into a DIGITAL C++ program and export DIGITAL C++ code and data for use with other languages. See The C++ Programming Language, 3rd Edition for details on the extern "C" declaration.

3.4 How to Organize Your C++ Code

This section explains the best way for DIGITAL C++ users to organize an application into files; it assumes that you are using automatic instantiation to instantiate any template classes and functions.

3.4.1 Code That Does Not Use Templates

The general rule is to place declarations in header files and place definitions in library source files. Thus, the following items belong in header files:

The following items belong in library source files:

Header files should be directly included by modules that need them. Because several modules may include the same header file, a header file must not contain definitions that would generate multiply defined symbols when all the modules are linked together.

Library source files should be compiled individually and then linked into your application. Because each library source file is compiled only once, the definitions it contains will exist in only one object module and multiply defined symbols are thus avoided.

For example, to create a class called "array" you would create the following two files:

Header file, array.h:


// array.h 
#ifndef ARRAY_H 
#define ARRAY_H 
 
class array { 
private: 
        int curr_size; 
        static int max_array_size; 
public: 
        array() :curr_size(0) {;}  
        array(int); 
}; 
 
#endif 

Library source file, array.cxx:


// array.cxx 
#include "array.h" 
 
int array::max_array_size = 256; 
 
array::array(int size) :  curr_size(size) { ...;} 

You would then compile the array.cxx library source file using the following command:


cxx -I./include array.cxx 
 

The resulting object file could either be linked directly into your application or placed in a library (see Section 3.4.3).

Note that the header file uses header guards, which is a technique to prevent multiple inclusion of the same header file.

3.4.2 Code That Uses Templates

With the widespread use of templates in C++, determining the proper place to put declarations and definitions becomes more complicated.

The general rule is to place template declarations and definitions in header files, and to place specializations in library source files.

Thus, the following items belong in template declaration files:

The following items can be placed either in the header file with the corresponding template declaration or in a separate header file that can be implicitly included when needed. This file has the same basename as the corresponding declaration header file, with a suffix that is found by implicit inclusion. For example, if the declaration is in the header file inc1.h, these corresponding definitions could be in file inc1.cxx.

The following must be placed in library source files to prevent multiple definition errors:

These guidelines also apply to nontemplate nested classes inside of template classes.

Note

Do not place definitions of nontemplate class members, nontemplate functions, or global data within template header files; these must be placed in library source files.

All these header files should use header guards, to ensure that they are not included more that once either explicitly or by implicit inclusion.

For example, the array class from Section 3.4.1, modified to use templates, could now look as follows:

Template declaration file array.h:


 
 // array.h 
 
 #ifndef ARRAY_H 
 #define ARRAY_H 
  
 template <class T> 
 class array { 
 private: 
         int curr_size; 
         static int max_array_size; 
 public: 
         array() :curr_size(0) {;} 
         array(T); 
 };  
  
 #endif 
 

Template definition file array.cxx:


 
 // array.cxx 
 template <class T> 
 int array<T>::max_array_size = 256; 
  
 template <class T> 
 array<T>::array(int size) :  curr_size(size) { ; } 
 

You would then create, as follows, the source file myprog.cxx that uses the array class:


 
 // myprog.cxx 
  
 #include <array.h> 
  
 main() { 
         array<int> ai; 
  
         // ... 
 } 
 


Previous Next Contents Index