在C和C ++中,如果我想在其他编译单元中使用全局变量,我将定义变量,如:
int g_myVal = 0;
这为int
分配存储空间。
在头文件中,我然后声明变量:
extern int g_myVal;
这通知编译器所述符号存在于某个其他编译单元中。然后由链接器来解析符号。
但是,如果我希望变量可用于" C"链接我必须定义变量(分配存储),如:
extern "C" int g_myVal = 0;
那么如何区分分配存储并仅通知编译器所述符号存在于另一个编译单元中?
答案 0 :(得分:8)
你的困惑源于extern
和extern "C"
做两件事的事实。
extern
extern
本身就是存储类说明符:
[C++11: 7.1.1/6]:
extern
说明符只能应用于变量和函数的名称。extern
说明符不能用于类成员或函数参数的声明。有关使用extern
说明符声明的名称的链接,请参见3.5。 [注意:extern
关键字也可用于显式实例化和连接规范,但它是在这种情况下不是存储类说明符。 -end note]
extern "C"
正如该尾随提示所暗示的,还有另一个上下文,您可以使用extern
关键字,并将其作为链接说明符:
[C++11: 7.5/2]:
使用 linkage-specification 可以实现C ++和非C ++代码片段之间的链接(3.5):联动规格:
extern
string-literal{
declaration-seq opt}
extern
string-literal声明
C ++喜欢重复使用关键字。
现在,默认情况下,标记有链接说明符的变量是声明而不是定义,因此从这个意义上说,就好像您还使用了extern
的其他含义:
[C++11: 7.5/7]:
直接包含在 linkage-specification 中的声明被视为包含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
的不同含义澄清代码中发生的事情。
答案 1 :(得分:1)
在这种情况下,将初始化程序= 0
更改为定义,这就是此处分配存储的原因。 (即使只是普通的extern
也会发生同样的情况。)