In C++, extern "C"
is a linkage specification that allows functions to be compiled with C linkage, making them accessible from C code. This tutorial will delve into the concept of linkage specification, its importance, and how to use extern "C"
effectively.
Introduction to Linkage Specification
Linkage specification in C++ refers to the way functions and variables are linked together during compilation. When compiling C++ code, the compiler performs name mangling on function names to support features like function overloading and namespaces. However, this makes it difficult for C code to call C++ functions directly.
The Role of extern "C"
The extern "C"
linkage specification tells the C++ compiler not to perform name mangling on a function or variable, allowing it to be linked with C code. This is essential when calling C functions from C++ code or vice versa.
Here’s an example:
extern "C" {
void foo();
}
In this example, the foo
function is compiled with C linkage, making it accessible from C code.
Using extern "C" Blocks
You can use extern "C"
blocks to group multiple declarations or definitions together. This makes it easier to manage large codebases and ensures that all functions within the block are compiled with C linkage.
extern "C" {
void foo();
int bar(int x);
}
Key Points to Remember
extern "C"
is a linkage specification, not a type of function or variable.- Every compiler must provide "C" linkage support.
- Linkage specifications can nest, with the innermost one determining the final linkage.
- Only function names and variable names with external linkage have a language linkage.
Examples and Use Cases
Here’s an example of calling C code from C++:
// c.h
#ifndef C_H
#define C_H
#ifdef __cplusplus
extern "C" {
#endif
int f();
#ifdef __cplusplus
}
#endif
#endif
// c.c
#include "c.h"
int f(void) { return 1; }
// main.cpp
#include <cassert>
#include "c.h"
int main() {
assert(f() == 1);
return 0;
}
To compile and run this example:
g++ -c -o main.o -std=c++98 main.cpp
gcc -c -o c.o -std=c89 c.c
g++ -o main.out main.o c.o
./main.out
Another example is calling C++ code from C. In this case, you need to manually create non-mangled versions of each function you want to expose:
// cpp.h
#ifndef CPP_H
#define CPP_H
#ifdef __cplusplus
// C cannot see these overloaded prototypes.
int f(int i);
int f(float i);
extern "C" {
#endif
int f_int(int i);
int f_float(float i);
#ifdef __cplusplus
}
#endif
#endif
// cpp.cpp
#include "cpp.h"
int f(int i) {
return i + 1;
}
int f(float i) {
return i + 2;
}
int f_int(int i) {
return f(i);
}
int f_float(float i) {
return f(i);
}
// main.c
#include <assert.h>
#include "cpp.h"
int main(void) {
assert(f_int(1) == 2);
assert(f_float(1.0) == 3);
return 0;
}
To compile and run this example:
gcc -c -o main.o -std=c89 -Wextra main.c
g++ -c -o cpp.o -std=c++98 cpp.cpp
g++ -o main.out main.o cpp.o
./main.out
Conclusion
In conclusion, extern "C"
is a powerful tool in C++ that allows for seamless integration with C code. By understanding how to use linkage specification effectively, you can create more versatile and compatible codebases.
When working with C++ and C code together, remember to use extern "C"
blocks to ensure proper linkage and avoid name mangling issues.