7

基于这个问题,我理解了将 C 库与 C++ 代码链接起来的构造的目的。现在假设以下情况:

我有一个用 C++ 编译器编译的“.so”共享库。头文件有一个'typedef stuct'和一些函数声明。如果标头包含 extern "C" 声明...

#ifdef __cplusplus
extern "C"
{
#endif

  // typedef struct ...;
  // function decls

#ifdef __cplusplus
}
#endif

……效果如何?具体来说,我想知道该声明是否有任何有害的副作用,因为共享库被编译为 C++,而不是 C。

在这种情况下是否有任何理由使用 extern "C" 声明?

4

5 回答 5

12

这很重要,因此编译器不会命名 mangle。C++ 使用名称修饰来区分具有运算符重载的函数。

对二进制文件运行“/usr/bin/nm”以查看 C++ 对函数名称的作用:_ZSt8_DestroyIN9__gnu_cxx17__normal_iteratorIPiSt6vectorIiSaIiEEEEiEvT_S7_SaIT0_E

extern "C" 防止该名称被修改。

IIRC,这使得程序可以在运行时动态链接符号。“插件”类型的架构很常见。

于 2010-04-06T19:27:25.740 回答
5

编译 C++ 时,方法名称会更改(修改) - 您将无法从另一个使用 C 的 dll/exe 调用该方法。

为了保留类和方法名称,您需要将它们编译为“C”而不进行名称修改。

该库仍然是一个 C++ 库,但它公开了它的一些声明(extern "c" 块中的那个)作为 C 方法。

于 2010-04-06T19:23:35.077 回答
3

#ifdef保护的extern声明是告诉 C 链接器符号具有 C(未损坏)符号表条目。这#ifdef确保 C 编译器编译的代码单元(文件)没有影响。

于 2010-04-06T19:27:21.010 回答
0

使用 C++ API 的一个不利因素extern "C"是它会阻止您出现函数重载:

extern "C"
{
    // ILLEGAL - C linkage does not support function overloading
    void foo(int x);
    void foo(const char *str);
}
于 2010-04-06T20:33:21.880 回答
0

示例中的#ifdef表示只有 C++ 编译器会看到extern包装的头文件,这意味着它将产生未损坏的名称。AC 编译器看不到extern(它不会理解),但总是产生未损坏的名称。

这意味着 C 和 C++ 编译器都将在其目标文件中生成相同的符号,因此无论哪个编译器为声明的函数生成目标代码,所有目标文件都将成功链接,因为符号具有相同的链接和相同的名称。

对于静态链接或与共享库的链接,应该没有任何影响。

于 2010-04-06T20:39:43.113 回答