以下代码段正常
extern int i;
int i;
int main(){
return 0;
}
我得到的是,'i'被声明然后被定义。由于只有一个定义,所以完全没问题。
int main(){
extern int i;
int i;
return 0;
}
现在,上面的一个给出了以下错误
new.cpp: In function ‘int main()’:
new.cpp:5:6: error: redeclaration of ‘int i’
int i;
^
new.cpp:4:13: note: previous declaration ‘int i’
extern int i;
问题出在这里?这里也有'i'的单一定义。
答案 0 :(得分:3)
要理解其中的差异,您需要熟悉C中名为暂定定义的概念。引用C标准:
C11,草案,§6.9.2,外部对象定义
具有文件范围的对象的标识符声明 没有初始化程序,没有存储类说明符或没有 存储类说明符静态,构成一个暂定的 定义。如果翻译单元包含一个或多个暂定单元 标识符的定义,翻译单元包含否 该标识符的外部定义,然后行为是完全正确的 好像翻译单元包含一个文件范围声明 标识符,在翻译结束时使用复合类型 单位,初始化程序等于0。
第一个代码段中的内容仅是i
的暂定定义。您可以根据需要为对象设置尽可能多的暂定定义(但只允许一个定义):
int i; // tentative definition
int i; // tentative definition
int i; // tentative definition
int main(void) {
return 0;
}
有效。
在这里,i
具有外部联系并暂时定义。如果i
在同一翻译单元的某个位置定义,那么这将是i
的实际定义。如果在翻译单元中找不到i
的其他定义,那么这将成为完整定义,就像定义如下:
int i = 0;
int main(void) {
return 0;
}
但第二个代码段int i;
不是一个暂定的定义。只能暂时定义具有外部链接的对象。在第二个片段中,声明extern int i;
表示i
在其他位置使用外部链接定义。但下一行int i;
表示i
定义没有链接(本地自动变量没有任何链接 - 这是不暂定定义)。因此i
的定义存在冲突。因此,第一个片段很好,但第二个不是。
答案 1 :(得分:0)
在第二种情况下,在一个范围内有两个i
声明。一个人说“在这个函数之外定义了一个变量i
”;另一个说“这个函数里面有一个变量i
”。没有新的范围,这是不允许的。
规则在内部和外部功能都不同。
请注意,您可以使用:
#include <stdio.h>
int i = 21;
int main(void)
{
extern int i;
i = 37;
{
int i = 57;
printf("%d\n", i);
}
printf("%d\n", i);
return 0;
}
编译好(除非在使用GCC或Clang时在编译选项中包含-Wshadow
),并在输出上生成57
和37
(由{{3指出)在CoffeeAndCode)。
另见comment