7

我正在编写一个 C++ 共享库供 C 程序使用。但是,我有一个关于externand的问题extern "C"

考虑以下代码

我的头文件是这样的:

#ifdef __cplusplus      
     extern "C" int global;
     extern "C" int addnumbers(int a, int b); 
 #else
      extern int global;
 #endif

这工作得很好;我只需要声明

int global;

在我的 .cpp 或我的 .c 文件中。但是,我不明白的是:

extern "C"和这里有什么区别extern?我尝试发表评论extern "C" int global并且它有效!为什么?

我知道那extern "C"是用来制作C链接的。这就是为什么我有extern "C" int addnumbers(int,int). 换句话说,如果我想编写一个要在 C 程序中使用的 C++ 函数,我会编写extern "C". 现在,全局变量呢?我猜这里的情况有所不同?我希望 C 程序使用名为 的 C++ 变量global,但我可以使用externnot extern "C"。这是为什么?这对我来说并不直观。

评论:我不认为这是重复的,因为我问的是当你将它用于变量和函数时有什么区别。

4

4 回答 4

16

通过附加extern "C"到您的 C++ 声明(对象和函数等),您可以为它们提供“C 链接” - 使它们可以从 C 代码访问。如果你省略了这个“语言链接”规范,编译器不会做任何努力来做正确的链接。在函数的情况下,这会导致链接失败,因为重整。在全局变量的情况下,一切都可以正常工作,因为变量不需要修改。

extern "C"但是,在我的系统(MS Visual Studio)上,如果我“忘记”在 C++ 头文件中指定链接规范,C 和 C++ 之间的链接将不起作用。错误信息示例:

error LNK2001: unresolved external symbol "int global" (?_global)

同时,当我检查包含global使用dumpbin实用程序定义的已编译 C++ 源代码时,我看到

00B 00000014 SECT4  notype       External     | ?global@@3HA (int global)

所以 MS Visual Studio 会破坏全局变量的名称,除非它们具有 C 链接——这使得 C 链接规范成为强制性的。


此外,请考虑以下示例:

namespace example {
    int global;
}

如果全局变量在命名空间内,C 代码将无法访问它。在这种情况下,所有编译器都需要 C++ 声明中的正确链接规范:

namespace example {
    extern "C" int global;
}

结论:

当您需要 C 链接时使用extern "C"- 无论它是函数还是全局变量。如果它是一个全局变量,它可能无论如何都可以工作,但不能保证(并且可能很危险)。

于 2016-07-05T16:48:32.693 回答
1

extern只是告诉编译器下一个变量(全局)可能尚未声明,但它在不同的翻译单元中声明为全局,并且在链接阶段,符号“全局”将与内存中的一个区域相关联。

正如一些人评论的那样, while extern "C"is 用于解决 C++ 中的名称修改问题,该函数将被addnumbers_i_i链接器称为(或类似的东西),而在 c 中它的符号是addnumbers

于 2016-07-05T15:05:36.563 回答
0

“C++ 有一个特殊的关键字来声明具有 C 绑定的函数:extern "C"。声明为 extern "C" 的函数使用函数名称作为符号名称,就像 C 函数一样。因此,只有非成员函数可以声明为 extern "C",并且它们不能被重载。”

C++ 中对于编译器生成的函数名称没有标准。关键字 extern "C" 指示编译器生成 C 标准中的函数名。

于 2016-07-01T11:10:28.940 回答
0

我发现 extern "C" 是用来制作 C++ 标准编译的 C++ 函数,它与变量无关,因为 C 和 C++ 中函数名的解决方案是不同的。如“void foo(int x, int y)”,C编译器将其翻译成“_foo”,而C++编译器将其翻译成“_foo_int_int”。

于 2016-07-01T13:21:38.380 回答