将extern "C"
放入C++代码到底是做什么的?
例如:
extern "C" {
void foo();
}
发布于 2012-10-20 17:08:32
只是想添加一些信息,因为我还没有看到它发布。
您经常会看到C头中的代码,如下所示:
#ifdef __cplusplus
extern "C" {
#endif
// all of your legacy C code here
#ifdef __cplusplus
}
#endif
这样做的目的是允许您在C++代码中使用C头文件,因为宏"__cplusplus“将被定义。但是,您还可以在遗留的C代码中使用它,其中宏没有定义,所以它不会看到唯一的C++构造。
不过,我也看到了一些C++代码,如:
extern "C" {
#include "legacy_C_header.h"
}
我想这也是同样的事情。
不知道哪条路更好,但我都看到了。
发布于 2015-05-29 02:06:31
g++
反编译生成的二进制文件,以查看发生了什么
main.cpp
void f() {}
void g();
extern "C" {
void ef() {}
void eg();
}
/* Prevent g and eg from being optimized away. */
void h() { g(); eg(); }
编译和反汇编生成的小精灵输出:
g++ -c -std=c++11 -Wall -Wextra -pedantic -o main.o main.cpp
readelf -s main.o
产出包括:
8: 0000000000000000 7 FUNC GLOBAL DEFAULT 1 _Z1fv
9: 0000000000000007 7 FUNC GLOBAL DEFAULT 1 ef
10: 000000000000000e 17 FUNC GLOBAL DEFAULT 1 _Z1hv
11: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND _GLOBAL_OFFSET_TABLE_
12: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND _Z1gv
13: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND eg
Interpretation
我们看到:
ef
和eg
存储在代码中同名的符号中。结论:下列两种符号类型均未被破坏:
Ndx = UND
),将在另一个对象文件的链接或运行时提供因此,在调用时需要同时使用extern "C"
:
g++
期待由gcc
产生的未损坏的符号g++
生成未损坏的符号供gcc
使用在 C中不起作用的东西
很明显,任何需要名称损坏的C++特性都不能在extern C
中工作。
extern "C" {
// Overloading.
// error: declaration of C function ‘void f(int)’ conflicts with
void f();
void f(int i);
// Templates.
// error: template with C linkage
template <class C> void f(C i) { }
}
C++示例中的最小可运行C
为了更完整和更好,也请参见:如何在C++项目中使用C源文件?。
从C++调用C非常容易:每个C函数只有一个可能的无损坏符号,因此不需要额外的工作。
main.cpp
#include <cassert>
#include "c.h"
int main() {
assert(f() == 1);
}
c.h
#ifndef C_H
#define C_H
/* This ifdef allows the header to be used from both C and C++
* because C does not know what this extern "C" thing is. */
#ifdef __cplusplus
extern "C" {
#endif
int f();
#ifdef __cplusplus
}
#endif
#endif
c.c
#include "c.h"
int f(void) { return 1; }
运行:
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
如果没有extern "C"
,链接将失败,原因如下:
main.cpp:6: undefined reference to `f()'
因为g++
希望找到一个损坏的f
,这是gcc
没有生产的。
C示例中的最小可运行C++
从C调用C++有点困难:我们必须手动创建每个要公开的函数的非损坏版本。
这里,我们将演示如何向C公开C++函数重载。
main.c
#include <assert.h>
#include "cpp.h"
int main(void) {
assert(f_int(1) == 2);
assert(f_float(1.0) == 3);
return 0;
}
cpp.h
#ifndef CPP_H
#define CPP_H
#ifdef __cplusplus
// C cannot see these overloaded prototypes, or else it would get confused.
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);
}
运行:
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
如果没有extern "C"
,它就会失败,因为:
main.c:6: undefined reference to `f_int'
main.c:7: undefined reference to `f_float'
因为g++
生成了gcc
找不到的损坏符号。
当我包含来自extern "c"
?的C头时,在哪里?
cstdio
)可能依赖于https://gcc.gnu.org/onlinedocs/cpp/System-Headers.html提到的#pragma GCC system_header
:“在某些目标(如RS/6000 AIX )上,GCC在编译为C++时隐式地将所有系统标头包围为'extern”C‘块。“但我没有完全确认它。”/usr/include/unistd.h
这样的POSIX在Ubuntu20.04上转载的:我需要一个外部的"C“块来包含标准的POSIX C头吗? (通过__BEGIN_DECLS
)进行了讨论。__BEGIN_DECLS
是通过#include <features.h>
包含的。在Ubuntu 18.04测试。
发布于 2009-06-24 21:22:05
在每个C++程序中,所有非静态函数都在二进制文件中表示为符号.这些符号是特殊的文本字符串,它们唯一地标识程序中的函数。
在C中,符号名与函数名相同。这是可能的,因为在C中,没有两个非静态函数可以具有相同的名称。
因为C++允许重载,并且有许多C不具备的特性--比如类、成员函数、异常规范--所以不能简单地使用函数名作为符号名。为了解决这个问题,C++使用了所谓的名称mangling,它将函数名和所有必要的信息(比如参数的数量和大小)转换为一些只由编译器和链接器处理的奇怪的字符串。
因此,如果您指定一个函数为extern C,编译器不会对它执行名称损坏,并且可以使用它的符号名作为函数名直接访问它。
这在使用dlsym()
和dlopen()
调用此类函数时非常方便。
https://stackoverflow.com/questions/1041866
复制相似问题