GCC不抱怨外部变量的重新定义?

时间:2017-11-14 14:52:51

标签: c gcc redefinition

这个简单的代码(MCVE):

#include <stdio.h>

int a = 3;
int main(){
    printf("%d\n", a);
    return 0;
}
int a; // This line

令我惊讶的是,GCC(MinGW GCC 4.8.2,4.9.2和6.3.0)没有给出任何错误,甚至没有关于标记线的警告!但是,如果我在第二个定义中为a分配值,则会这样做。

更奇怪的是,g++告诉我第二次重新定义是错误,但gcc没有。

它不应该是对现有变量的重新定义,因为没有关键字extern吗?

2 个答案:

答案 0 :(得分:3)

来自C标准(6.9.2外部对象定义)

  

1如果对象的标识符声明具有文件范围和   初始化程序,声明是的外部定义   标识符

  

2具有文件范围的对象的标识符声明   没有初始化程序,没有存储类说明符或没有   存储类说明符static,构成暂定   定义即可。如果翻译单元包含一个或多个暂定单元   标识符的定义,翻译单元包含否   该标识符的外部定义,然后行为是完全正确的   好像翻译单元包含一个文件范围声明   标识符,在翻译结束时使用复合类型   单位,初始化程序等于0。

C标准中有一个例子

int i1 = 1; // definition, external linkage
//...
int i1; // valid tentative definition, refers to previous

所以在你的程序中这个声明

int a = 3;

是标识符a

的外部定义

和这一个

int a;

是一个暂定的定义,指的是标识符的先前外部定义。

如果要在第二个声明中使用初始化程序,那么您将获得标识符的两个外部定义,编译器将发出错误,因为只能存在一个外部定义。

考虑到C和C ++相对于此上下文的不同,

来自C ++标准(C.1.2第6章:基本概念)

6.1

  

更改:C ++没有C中的“暂定定义”。例如,在   文件范围,

int i;
int i;
  

在C中有效,在C ++中无效。

答案 1 :(得分:2)

在C中称为暂定定义

Cppreference说:

  

暂定定义

     

暂定定义是没有的外部声明   初始化程序,并且没有存储类说明符或者没有   说明符静态的。

     

暂定定义是一种可能会或可能不会充当的声明   定义。如果先前或稍后找到实际的外部定义   在同一个翻译单元中,暂定的定义就是行动   作为宣言。

     

[...]

int i3; // tentative definition, external linkage

int i3; // tentative definition, external linkage 

extern int i3; // declaration, external linkage