extern和extern "C"用于变量的声明

10

我正在为一个C程序编写C++共享库。但是,我有关于externextern "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"extern在这里有什么区别?我尝试注释掉extern "C" int global,它仍然可以正常工作!为什么呢?

我知道extern "C"用于创建C语言链接。这就是为什么我有extern "C" int addnumbers(int,int)的原因。换句话说,如果我想编写一个C++函数供C程序使用,我会使用extern "C"。那么,全局变量怎么办——我猜这里的情况不同?我希望C程序使用名为global的C++变量,但我可以使用extern而不是extern "C"。为什么呢?这对我来说不太直观。

注释:我认为这不是重复问题,因为我想知道在将变量与函数用作参数时的区别。


2
我认为这不是重复的,因为我想知道在使用它时用于变量和函数时的区别是什么。 - Thenewstockton
2
你不会看到extern "C"和extern变量之间的区别,因为编译器对变量名不做任何处理。它只影响函数名。 - AnatolyS
https://dev59.com/P3NA5IYBdhLWcg3wPLP-#1041880 - user6464825
就我个人而言,公开全局变量的库不是一个好主意。 - Oliver Charlesworth
@AnatolyS,您能详细说明外部变量不适用的原因吗?AnandS提供的链接似乎提到了相反的情况。 - mgouin
显示剩余2条评论
4个回答

19

通过在你的C++声明(对象和函数)上附加extern "C",可以为它们提供"C语言链接",从而使它们可以从C代码中访问。如果省略了这个"语言链接"规范,编译器就不会做任何努力进行适当的链接。对于函数来说,这会导致链接失败,因为名称重整。对于全局变量来说,一切可能都正常工作,因为变量不需要名称重整。

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

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

当我使用dumpbin工具检查包含global定义的编译后的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" - 不管是函数还是全局变量都一样。如果是全局变量,它可能会起作用,但不能保证(并且可能是危险的)。


关于全局变量和命名空间作用域变量的混淆,你的回答和见解非常好! - Gabriel Staples
如果我有一个在C++文件中声明的变量,并且我希望它具有C链接,该怎么办?我不能将其设置为"extern "C"",因为这样做会使它成为"extern",而实际上它是在本地定义的。它是全局变量,但在C++文件中定义。 - Yan King Yin
简短回答:extern "C"并不意味着extern。但是你应该使用“提问”按钮来获取一个正确的答案。 - anatolyg

2

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

extern "C"用于解决C ++中名称重整的问题,此函数将由链接器称为addnumbers_i_i(或类似名称),而在C中其符号为addnumbers


2
实际上,extern 被放置在变量的 声明 中,以表明它在其他地方被 定义,以避免 定义 一个新变量(与另一个同名变量)可能导致链接器失败,并且当您想要共享单个全局变量时并不是您需要的。 - JimmyB

0

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

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


0

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接