[Home]
[Search]
[Contents]
Mixing Languages
Digital Mars C++ supports linkage with C, FORTRAN, and Pascal functions.
This chapter describes the function-naming and parameter-passing conventions
for linking these languages. It also details the DMC++
implementation of type-safe linkage, which
allows the linker to check the types of function arguments across
separately compiled modules and lets the programmer use the same
function name for different functions.
For information about calling assembly language routines from C or
C++, see Using Assembly Language Functions.
What's in This Chapter
- The DMC++ implementation of type-safe linkage.
- How DMC++ implements C++ linkage.
- How DMC++ implements C linkage.
- How to mix C and C++ modules.
- Name mangling in C++.
- How DMC++ implements Fortran and Pascal
linkage.
Type-Safe Linkage
The Digital Mars C++ implementation of type-safe linkage is designed
to make it easy for you to call, from a C++ program, a function
written in another language or vice versa. The system Digital Mars uses
is identical to the one described in the Microsoft Object Mapping
Specification, published by Microsoft's Language Business Unit.
Type-safe linkage is an important feature of DMC++, even if
you are only linking C++ modules. It lets you overload functions
(give different functions the same name) because it provides the
linker with a unique identifier for each function. The compiler
mangles the name you give a function, in combination with the
number and type of its arguments, to produce a unique identifier for
the linker.
Problems with traditional (unsafe) C linkage
Traditional C linkage mechanisms are unsafe because they give the
compiler no viable way to check the types of function arguments
across separately compiled program modules. This deficiency can
cause serious problems at compile time. For instance, suppose the
following function is defined in a header file:
void checkit(unsigned char c);
where c is defined as unsigned char because some of the values
it needs to check for are in the range 128 through 255. This header is
typically included in the file that defines checkit.
As is also common in C programming, checkit is used in a second
file. Rather than include the header file, the programmer (per
convention) separately declares the prototype for checkit at the
top of the second file. The following prototype is used:
void checkit(char c);
If the program is compiled on a system that uses unsigned chars by
default, the above code compiles and executed perfectly. However,
if the program is then ported to a compiler where chars are signed
by default (like DMC++), the program yields unpredictable
results because the call to checkit in the second file treats values
over 127 as negative.
Bugs of this type can prove very difficult to find because the
compiler processes one file at a time and therefore cannot detect
type violations in function prototypes across files. But with type-safe
linkage, the compiler generates two different internal (hidden)
identifiers for the two prototypes. Since no matching function is
provided for the second prototype, the linker flags this external
function reference as unresolved.
Advantages of type-safe linkage
Type-safe linkage offers these important advantages over traditional
C linkage:
- You can overload C++ functions without using the
overload keyword.
- The linker automatically checks the types of function
arguments across modules.
- The compiler provides improved error checking and error
reporting with respect to type mismatches.
This system still allows linkage to external libraries and precompiled
C code without having to recompile them. It is also more flexible
than modifying function linkage with the __cdecl, __pascal, or
__fortran keywords alone. However, each linkage type
(Digital Mars C++ supports FORTRAN and Pascal linkage, in addition to
the built-in C++ and C linkage specifications) differs from the others
in function-naming, parameter-passing conventions, or both,
depending on the target environment.
C++ Linkage
C++ linkage is the linkage type the C++ compiler uses by
default.
Function naming
The C++ compiler mangles the names of functions with
C++ linkage to include information on the number and types of
arguments they take. For member functions, information as to the
class to which a function belongs is also included.
Overloading
All functions are automatically overloaded. Whenever a new version
of a function is defined, it must have a prototype that the compiler
can distinguish; otherwise, it cannot be overloaded. Because the
internal name for each function is unique, the compiler can resolve a
function call to the correct version of the overloaded function, even
if it occurs in a third-party external library. Since the overloading of
functions is automatic, the overload keyword is redundant
(although it is still allowed). Do not use the overload keyword in
new code because it could be removed from the C++ language
definition.
If you accidentally overload a function (that is, if you declare it twice
with different argument types), one of these functions will not have
a function definition with matching argument types, and the linker
will report an unresolved external reference. This happens even if
the re-declarations occur in two separately compiled modules.
How the compiler treats functions with C++ linkage
The compiler performs these operations on functions with C++
linkage:
- It mangles all function names (that is, type information is
appended to the function name).
- For functions that take a fixed number of arguments:
- It pushes arguments from left to right onto the stack
before the function is called (the rightmost argument
is closest to the stack pointer).
- The called function (not the caller) cleans the
arguments off the stack. On 8086-based processors,
this is accomplished via the RET N instruction, where
N is the number of bytes on the stack.
- It returns structures by allocating a temporary variable
on the stack and passing a hidden pointer to it. The
called function copies the return values into the
temporary variable and returns a pointer to it. This
method is reentrant.
- It returns floats and doubles in registers (unlike
Microsoft C). This method is reentrant.
- For functions that take a variable number of arguments:
- It pushes arguments from right to left onto the stack
before the function is called (the leftmost argument is
closest to the stack pointer).
- The caller of the function cleans the arguments off the
stack.
- It returns floats and doubles in registers (unlike
Microsoft C). This method is reentrant.
- It returns structures that are 1, 2, or 4 bytes long in
registers. Larger structures are returned by creating a
temporary variable in a static buffer, copying the
return value into the buffer, and returning a pointer to
it. This method is not reentrant.
Mixing C++ linkage with other linkage types
C does not support C++ linkage. You can call C functions
from C++ code but you cannot call C++ functions from C code.
With the C++ compiler, you can use the syntax:
extern "C++" { }
to specify C++ linkage when the declaration of a C++ function is
nested inside declarations for some other linkage type. See the
section "Type-Safe Linkage" in this chapter for more information.
Note:
The __near and __far keywords are ignored for
member functions and always use the default for
the memory model used. This behavior simplifies
the implementation of virtual functions.
C Linkage
The C linkage method allows programs written in C++ to link with
and call C library functions. C linkage has the same effect with the
C++ compiler as the __cdecl keyword has with the C compiler.
C linkage is the default linkage for .c files when compiled without
the -cpp flag. If a function is declared as using C linkage, and a
function definition is found in the C++ source file, that function is
compiled as a C function and not as a C++ function. Any calls to that
function from other C++ functions are handled correctly.
Digital Mars's C linkage is compatible with the C linkage used by the
Microsoft C compiler.
How the compiler treats functions with C linkage
The compiler treats functions with C linkage as follows:
- It prefixes an underscore (_) to all global names.
- It does not mangle function names.
- It pushes arguments from right to left onto the stack
before the function is called (the leftmost argument is
closest to the stack pointer).
- The caller of the function cleans the arguments off the
stack.
- It returns structures that are 1, 2, or 4 bytes long in
registers. It returns larger structures by creating a
temporary variable in a static buffer and passing a hidden
pointer to it. This method is not reentrant.
- It returns floats and doubles in registers (unlike
Microsoft C). This method is reentrant.
Specifying C linkage in C++ code
In C++ code, use this syntax to specify C linkage:
extern "C" { }
In C code, you can specify C linkage explicitly by using the
__cdecl type modifier, provided you do not require strict ANSI C
compatibility.
Note:
The compiler recognizes the main function as
special and always compiles it with C linkage.
Mixing C and C++ Modules
C++ lets you call a C function from a C++ program. Only
minor changes to header files typically are required.
Compatibility with existing source code Every effort has been made to maximize
compatibility between
DMC++ and other C++ and C compilers, but you may need to
take some precautions when compiling code written with other
compilers. See Chapter 22, "Switching to Digital Mars C++," for
information.
Compatibility with earlier versions of Digital Mars C++
Programs that compiled under earlier versions of DMC++
should compile and run with only minor modifications under
Version 7. However, you need to recompile all your code because of
differences in the way the new compiler stores objects in memory.
You might also need to make some changes to header files to
account for the new compiler's more stringent type checking.
Recompiling C code as C++ code
We recommend that you rename your C modules with an extension
that the compiler recognizes as a C++ file extension, or compile with
the -cpp switch, so that your C functions use the default C++
linkage. This provides the benefit of cross-module type checking for
those functions. Recompiling C functions as C++ functions also
means an increase in speed because the compiler can use the more
efficient C++ parameter-passing method.
If you wish to retain C linkage for functions that call assembly
language routines, remember to ensure that the interface to C++ is
correct (see
Using Assembly Language Functions
for information).
Using existing C libraries
If you need to link separately compiled C and C++ object files, use
an existing C library without having to recompile it, or use assembly
language routines that have been designed to interface to C. You
need to ensure that the C++ modules use the right linking
conventions when calling functions contained in C or assembly
language modules.
Unless your C modules are compiled with a third-party C compiler,
you do not have to recompile them. Follow the steps below to
generate an object file and associated header files that you can link
to both C and C++ modules. All that is required is a modification of
the associated header files.
Note:
When constructing makefiles, be sure to run the
right compiler for each file. The default extension
for C files is .c. Valid extensions for C++ files are
.cpp, .cxx, or .cc.
Changing the header files
To modify an existing C library to work with Digital Mars C++, insert
the following code at the beginning of each header file:
#ifdef __cplusplus
extern "C" {
#endif
And, at then end of the file, insert this code:
#ifdef __cplusplus
}
#endif
You can then use the header with both C and C++ files.
Where it is undesirable to modify the header file, you can use the
following technique to encapsulate the #include statement in the
source file:
extern "C" {
#include "c_header.h"
}
Prototyping the functions in a library
If, after linking your program with a library, you get one or more
linker error messages about unprototyped functions, it is likely that
not all of the functions contained in the library are prototyped in the
header files for the library. You need to provide prototypes for those
functions that do not have them and place them in the header files.
You know which functions require prototyping by looking at the
first part of the function name reported by the linker, up to the
underscore. The procedure is the same for assembly language
functions.
Once you have modified a header file, you should be able to use the
library without difficulty, provided you always include the required
headers for the functions you use (as you must for the standard C
libraries supplied with the compiler).
Name Mangling in Digital Mars C++
Name mangling refers to the way in which the compiler alters
function names internally so that it can track member functions,
function overloading, and argument types.
The general layout for the DMC++ name mangling is
described in the Microsoft Object Mapping Specification, published
by Microsoft's Language Business Unit.
The basis for this name mangling is the function name itself, with an
added signature that holds information about the class (if any) to
which the function belongs and the number and types of its
arguments.
When constructing a C++ function name, the compiler takes the
original function name as the root of the encoded name. If the
function being encoded is a C++ operator, the compiler must also
supply a function name to represent the operator.
To view the mangled names of your functions, compile them and
then use the
DUMPOBJ or
OBJ2ASM utilities to view the resulting
object file, or link the code and run the
UNMANGLE
utility on the executable or map file.
You can also examine mangled names in a compiled program with
the Digital Mars C debugger or with the Digital Mars C++ debugger in
pure C mode.
FORTRAN and Pascal Linkage
The FORTRAN and Pascal linkage types let you link
C++ code to code written in other languages that use FORTRAN or
Pascal calling conventions.
In DMC++, the FORTRAN and Pascal linkage types behave
identically. However, you should use the appropriate specifier for
functions of each type because the calling conventions for FORTRAN
and Pascal may differ in future releases or on other platforms.
Compilation of functions with FORTRAN/Pascal linkage
The compiler treats functions with FORTRAN or Pascal linkage as
follows:
- It does not prefix an underscore (_) to global names.
- It converts all global names to uppercase.
- It does not append type information to function names.
- It pushes arguments onto the stack from left to right.
- The called function cleans the stack.
- Structures, floats, and doubles are returned by
allocating a temporary variable on the stack and passing a
hidden pointer to it. The called function copies the return
values into this variable and returns a pointer to it. This
method is reentrant.
Specifying FORTRAN/Pascal linkage in C code
In C code, use the __pascal type modifier to get Pascal linkage
and the __fortran type modifier to get FORTRAN linkage,
provided you do not require strict ANSI C compatibility.
Specifying FORTRAN/Pascal linkage in C++ code
In C++ code, use this syntax to specify Pascal or FORTRAN linkage:
extern "Pascal" { }
or
extern "FORTRAN" { }
You cannot use the C++ syntax in C programs.
Warning:
Although the FORTRAN and Pascal linkage methods
allow C++ programs to call functions of these types
or vice versa, they do not handle any other required
conversions. For example, conversions of NULL-
terminated C++ strings into Pascal strings with a
length prefix are not automatic.
__cdecl, __fortran, and __pascal
In Digital Mars C++, it is possible to call functions that do not use
the default function calling conventions. For instance, system
functions in the Microsoft Windows API use Pascal calling
conventions. The keywords __cdecl, __fortran, and __pascal
tell the C compiler that the functions to which they refer use the
calling and parameter-passing conventions of C, FORTRAN, or
Pascal, respectively, rather than the default conventions. In this
respect, they work in the same way as extern "C", extern
"FORTRAN", and extern "Pascal" do in the C++ compiler,
except that the extern format also engages the function-naming
conventions of the indicated language.
Note:
Although you can use these keywords in both C
and C++, use them with caution. The preferred
method to use with C++ is the extern "C",
extern "FORTRAN" or extern "Pascal"
syntax. This will make the C++ code portable to
other C++ compilers.
For example, to declare Pascal-calling conventions in C:
extern int __pascal my_function();
in C++:
extern "Pascal" int my_function();
Declaring data as __cdecl, __fortran, or __pascal influences
how the name appears to the linker. However, the name always
appears to the debugger as it appears in the source. __cdecl
causes an underscore to be added to the front of the name, which is
the default. __fortran or __pascal causes the name to convert
to upper case. For example, the following code appears as blang to
the linker:
int __pascal blang;
Notice that the keyword appears immediately before the variable
name.
Note:
If you do not use __cdecl, __fortran,
__pascal, or the extern functions, the compiler
mangles variable names according to Microsoft
specifications. This deviates from the ARM
description, which recommends that names not be
mangled.
Portability of Extended Keywords
One useful
method of ensuring portability to other systems is by
conditionally defining the extended keywords as empty:
// Remove extended keywords for non Digital Mars
// compilers
#if !defined(__DMC__)
#define __cdecl
#define __pascal
#define __fortran
#endif
Note:
In general, function pointers can cause subtle problems when the
function pointed to is not the compiler's default type. The rule to
remember is that the extended keyword must appear immediately
before the *, which determines that the type is a function pointer.
The correct syntax for declaring a pointer to a
Pascal function is:
int (__pascal *fp)(void);