声明“extern “C””有什么作用?在标头中为 C++共享库?
基于这个问题我理解链接C的构造的目的带有 C++ 代码的库。现在假设如下:
我有一个用 C++ 编译器编译的“.so”共享库。标头有一个“typedef Stuct”和许多函数声明。如果标头包含 extern "C" 声明...
#ifdef __cplusplus
extern "C"
{
#endif
// typedef struct ...;
// function decls
#ifdef __cplusplus
}
#endif
...效果是什么?具体来说,我想知道该声明是否有任何有害的副作用,因为共享库被编译为 C++,而不是 C。
在这种情况下是否有任何理由使用 extern“C” 声明?
Based on this question I understand the purpose of the construct in linking C libraries with C++ code. Now suppose the following:
I have a '.so' shared library compiled with a C++ compiler. The header has a 'typedef stuct' and a number of function declarations. If the header includes the extern "C" declaration...
#ifdef __cplusplus
extern "C"
{
#endif
// typedef struct ...;
// function decls
#ifdef __cplusplus
}
#endif
... what is the effect? Specifically I'm wondering if there are any detrimental side effects of that declaration since the shared library is compiled as C++, not C.
Is there any reason to have the extern "C" declaration in this case?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
这很重要,这样编译器就不会命名 mangle。 C++ 使用名称修饰来区分具有运算符重载的函数。
针对二进制文件运行“/usr/bin/nm”以查看 C++ 对函数名称执行的操作:
_ZSt8_DestroyIN9__gnu_cxx17__normal_iteratorIPiSt6vectorIiSaliEEEEiEvT_S7_SaIT0_E
extern "C" 可防止名称损坏。
IIRC,这使得程序可以在运行时动态链接符号。这对于“插件”类型的架构来说很常见。
This is important so that the compiler doesn't name mangle. C++ uses name mangling to differentiate functions with operator overloads.
Run "/usr/bin/nm" against a binary to see what C++ does with your function names:
_ZSt8_DestroyIN9__gnu_cxx17__normal_iteratorIPiSt6vectorIiSaIiEEEEiEvT_S7_SaIT0_E
extern "C" prevents that name mangling.
IIRC, that makes it possible for program to dynamically link in symbols at run time. It's common for "plugin" type architectures.
编译 C++ 时,方法名称发生更改(重整) - 并且您将无法从使用 C 的另一个 dll/exe 调用该方法。
为了保留类和方法名称,您需要将它们编译为“C”而不需要名称修改。
该库仍然是一个 C++ 库,但它将其一些声明(extern“c”块中的声明)公开为 C 方法。
When compiling C++ the method name changes (mangling) - and you won't be able to call that method from another dll/exe that uses C.
In order to keep the class and method name you need to compile them as "C" without name mangling.
The library is still a C++ library but it exposes some of its declarations (the one in the extern "c" block) as C methods.
#ifdef
受保护的extern
声明是为了告诉 C 链接器这些符号具有 C(未损坏的)符号表条目。#ifdef
确保 C 编译器编译的代码单元(文件)不会产生任何影响。The
#ifdef
guardedextern
declaration is to tell C linkers that the symbols have C (unmangled) symbol table entries. The#ifdef
ensures that there is no effect in the code unit (file) compiled by a C compiler.对 C++ API 使用
extern "C"
的一个缺点是它会阻止您出现函数重载:One detriment to using
extern "C"
for a C++ API is that it prevents you from having function overloads:示例中的#ifdef 意味着只有 C++ 编译器才会看到包装头文件的 extern,这意味着它将生成未损坏的名称。 AC 编译器看不到 extern(它无法理解),但总是生成未损坏的名称。
这意味着 C 和 C++ 编译器都将在其目标文件中生成相同的符号,因此无论哪个编译器为声明的函数生成目标代码,所有目标文件都将成功链接,因为符号具有相同的链接和相同的名称。
对于静态链接或与共享库的链接应该没有任何影响。
The
#ifdef
in the example means that only a C++ compiler will see theextern
wrapping the header file which will mean that it will produce non-mangled names. A C compiler doesn't see theextern
(which it wouldn't understand), but always produces non-mangled names.This means that both C and C++ compilers will produce the same symbols in their object files, so whichever compiler produces object code for the declared functions, all the object files will successfully link because symbols have the same linkage and the same name.
There should be no implications for either statically linking, or linking with a shared library.