关于全局变量的外部声明"C"外部声明

Extern declaration on an extern "C" global variable

本文关键字:外部 声明 全局变量      更新时间:2023-10-16

在C和C++中,如果我想在其他编译单元中使用全局变量,我会定义如下变量:

int g_myVal = 0;

这将为int分配存储。

然后在头文件中,我声明变量:

extern int g_myVal;

这通知编译器所述符号存在于某个其他编译单元中。然后由链接器来解析符号。

但是,如果我希望变量与"C"链接可用,我必须定义变量(分配存储),如:

extern "C" int g_myVal = 0;

那么,如何区分分配存储和仅仅通知编译器所述符号存在于另一个编译单元中呢?

您的困惑源于externextern "C"做两件不同的事情。


关于extern

extern本身就是存储类说明符:

[C++11: 7.1.1/6]:extern说明符只能应用于变量和函数的名称。extern说明符不能用于类成员或函数参数的声明中。有关用extern说明符声明的名称的链接,请参见3.5[注意:extern关键字也可以用于显式实例化链接规范,但在此类上下文中,它不是存储类说明符--结束注释]


关于extern "C"

正如后面的注释所暗示的,还有另一个上下文可以在其中使用extern关键字,即作为链接说明符

C++和非C++代码片段之间的[C++11: 7.5/2]:链接(3.5)可以使用链接规范来实现:

链接规范:
nbsp extern字符串文字{声明seqopt}
 nbsp;extern字符串文字声明

C++喜欢重复使用关键字。


声明与定义

现在,默认情况下,用链接说明符标记的变量是声明,而不是定义。因此,从这个意义上讲,就好像您也使用了extern:的其他含义

[C++11: 7.5/7]:直接包含在链接规范中的声明被视为包含extern说明符(7.1.1),用于确定声明名称的链接以及它是否是定义。此类声明不得指定存储类别[示例:

extern "C" double f();
static double f(); // error
extern "C" int i; // declaration
extern "C" {
int i; // definition
}
extern "C" static void g(); // error

—结束示例]

正如您在上面的示例中看到的,当您使用链接说明符时,仍然可以声明或定义。

这是另一个例子:

// Everything in this block has C linkage
extern "C" {
// Declaration of g_myVal
extern int g_myVal;
// Definition of g_myVal2
int g_myVal2;
}
int main()
{
g_myVal2 = 5;  // ok
g_myVal  = 6;  // not okay - linker error, symbol not found
}

现场演示


添加初始化程序时

话虽如此,g_myVal作为声明的处理被您使用的初始化器所否决,这迫使该声明成为一个定义:

[C++11: 7/8]:在一般声明形式中发现的语法组件之外的语法组件被添加到函数声明中,以形成函数定义但是,对象声明也是一个定义,除非它包含extern说明符并且没有初始值设定项(3.1)。定义会保留适当的存储量并完成任何适当的初始化(8.5)。

我希望这能澄清代码中extern的不同含义。

在这种情况下,放置初始值设定项= 0将声明更改为定义,这就是为什么在此处分配存储的原因。(即使只有普通的extern也会发生同样的情况。)