Previous | Contents | Index |
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:
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
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.
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.
DIGITAL C++ supports the following message information options. Both
are disabled by default.
Example:
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.
Example:
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.
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.
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.
-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
-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.
2.5 Message Information Options
"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.
cxx -msg_display_tag t.cxx
cxx: ... is nonstandard ("int" assumed) (D:nonstd_implicit_int)
cxx -msg_disable nonstd_implicit_int t.cxx
-msg_display_number
The error number is displayed at the beginning of each message issued.
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 Environment3.1 Using Existing C Header Files
3.1.1 Providing C and C++ Linkage
#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 |
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:
extern "C" int myroutine(int, float); |
cxx -c tiny.cxx cxx -v tiny.o |
/usr/lib/cmplrs/cxx/cc -G 8 -g0 -O1 -call_shared \ /usr/lib/cmplrs/cxx/_main.o tiny.o -v -lcxxstd -lcxx -lexc \ |& /usr/lib/cmplrs/cxx/demangle |
/usr/lib/cmplrs/cc/ld -g0 -O1 -call_shared /usr/lib/cmplrs/cc/crt0.o \ /usr/lib/cmplrs/cxx/_main.o tiny.o -lcxxstd -lcxx -lexc -lc |
/usr/lib/cmplrs/cxx/_main.o -lcxxstd -lcxx -lexc |
/usr/lib/cmplrs/cc/crt0.o ...-lc |
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.
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 |