digitalmars.com                        
Last update Sun Mar 4 11:58:06 2018

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

Type-Safe Linkage

The Digital Mars C++ implementation of type-safe linkage is designed to make it easy 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 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: 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:

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:

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

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); 

Home | Runtime Library | IDDE Reference | STL | Search | Download | Forums