这个简单的代码(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
吗?
答案 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中称为暂定定义。
暂定定义
暂定定义是没有的外部声明 初始化程序,并且没有存储类说明符或者没有 说明符静态的。
暂定定义是一种可能会或可能不会充当的声明 定义。如果先前或稍后找到实际的外部定义 在同一个翻译单元中,暂定的定义就是行动 作为宣言。
[...]
int i3; // tentative definition, external linkage int i3; // tentative definition, external linkage extern int i3; // declaration, external linkage