变量可以声明为static还是extern?

21 c c++ linkage storage-class-specifier

为什么以下不编译?

...
extern int i;
static int i;
...
Run Code Online (Sandbox Code Playgroud)

但如果你颠倒了订单,那就很好.

...
static int i;
extern int i;
...
Run Code Online (Sandbox Code Playgroud)

这里发生了什么?

Jac*_*ley 18

当它讨论声明外部或内部链接的复杂性时,这在C++标准中作为示例特别给出.这是在第7.1.1.7节中,它具有以下功能:

static int b ; // b has internal linkage
extern int b ; // b still has internal linkage

extern int d ; // d has external linkage
static int d ; // error: inconsistent linkage
Run Code Online (Sandbox Code Playgroud)

第3.5.6节讨论了extern在这种情况下应该如何表现.

发生的事情是:( static int i在这种情况下)是一个定义,其中static指示i具有内部链接.当extern在之后发生static编译器看到该符号已经存在,并且接受它已经具有内部连接并进行.这就是你的第二个例子编译的原因.

extern另一方面,是一个声明,它含蓄地指出,符号有外部链接,但实际上并没有创造任何.由于i在您的第一个示例中没有编译器注册i为具有外部链接,但是当它到达您的时它会static发现不兼容的语句,它具有内部链接并给出错误.

换句话说,这是因为声明比定义"更柔和".例如,您可以多次声明相同的事情而不会出现错误,但您只能定义一次.

C中是否相同,我不知道(但下面的netcoder的答案告诉我们C标准包含相同的要求).


net*_*der 10

对于C,引用标准,在C11 6.2.2中:标识符的链接:

3)如果对象或函数的文件范围标识符的声明包含存储类说明符static,则标识符具有内部链接.

4)对于extern在范围内使用存储类说明符声明的标识符,其中该标识符的先前声明是可见的,如果先前声明指定内部或外部链接,则后面声明中的标识符的链接与在先前声明中指定的联系.如果没有先前声明可见,或者先前声明未指定链接,则标识符具有外部链接.

(重点矿)

这解释了第二个例子(i将有内部联系).至于第一个,我很确定它是未定义的行为:

7)如果在翻译单元内,同一标识符同时出现内部和外部链接,则行为未定义.

...因为使用内部链接声明标识符之前extern出现,6.2.2/4不适用.因此,有内部和外部联系,所以它是UB.i

如果编译器发出诊断信息,我猜你很幸运.它可以无误地编译,并且仍然符合标准.