为什么 'extern' 存储 class 的功能不同?
Why 'extern' storage class works differently in functions?
以下代码片段工作正常
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'.
的单一定义
第二种情况,在一个作用域中有两个i
的声明。一个说 "there is a variable i
defined outside this function";另一个说 "there is a variable i
defined inside this function"。没有新的范围,这是不允许的。
函数内外规则不同
请注意,您可以使用:
#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
(如 CoffeeAndCode in a ).
另见 How do I use extern
to share variables between source files?
要理解区别,需要熟悉C语言中的一个概念,叫做暂定定义。引用C标准:
C11,草案,§6.9.2,外部对象定义
A declaration of an identifier for an object that has file scope
without an initializer, and without a storage-class specifier or with
the storage-class specifier static, constitutes a tentative
definition. If a translation unit contains one or more tentative
definitions for an identifier, and the translation unit contains no
external definition for that identifier, then the behavior is exactly
as if the translation unit contains a file scope declaration of that
identifier, with the composite type as of the end of the translation
unit, with an initializer equal to 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
存在定义冲突。因此,第一个片段很好,但第二个片段不是。
以下代码片段工作正常
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'.
的单一定义第二种情况,在一个作用域中有两个i
的声明。一个说 "there is a variable i
defined outside this function";另一个说 "there is a variable i
defined inside this function"。没有新的范围,这是不允许的。
函数内外规则不同
请注意,您可以使用:
#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
(如 CoffeeAndCode in a
另见 How do I use extern
to share variables between source files?
要理解区别,需要熟悉C语言中的一个概念,叫做暂定定义。引用C标准:
C11,草案,§6.9.2,外部对象定义
A declaration of an identifier for an object that has file scope without an initializer, and without a storage-class specifier or with the storage-class specifier static, constitutes a tentative definition. If a translation unit contains one or more tentative definitions for an identifier, and the translation unit contains no external definition for that identifier, then the behavior is exactly as if the translation unit contains a file scope declaration of that identifier, with the composite type as of the end of the translation unit, with an initializer equal to 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
存在定义冲突。因此,第一个片段很好,但第二个片段不是。