【发布时间】:2013-01-24 10:58:30
【问题描述】:
extern int a;
int a = 1;
int main(void)
{
return 0;
}
这是 UB 吗?标准在 6.2.2/7 中说
如果在一个翻译单元中,相同的标识符同时出现在内部和外部 链接,行为未定义。
【问题讨论】:
extern int a;
int a = 1;
int main(void)
{
return 0;
}
这是 UB 吗?标准在 6.2.2/7 中说
如果在一个翻译单元中,相同的标识符同时出现在内部和外部 链接,行为未定义。
【问题讨论】:
这是完全定义的行为。这就是编译器在包含头文件后进行预处理后得到的结果。
你的困惑似乎来自:
int a = 1;
没有内部链接。在文件范围a 具有外部链接。如果添加了static 说明符,它将具有内部链接。
【讨论】:
默认链接是extern。 extern 说明符表示它可能在另一个翻译单元或同一个翻译单元中定义和初始化。 extern 声明的相对位置无关紧要,否则它们会有些危险。
C99 TC2 §6.9.2/1
如果对象标识符的声明具有文件范围和初始化程序,则该声明是标识符的外部定义。
下面是一个例子:
int i1 = 1; // definition, external linkage
…
extern int i1; // refers to previous, whose linkage is external
【讨论】:
答案是肯定的和否定的。
如果a 在同一翻译单元的其他地方定义,那么是的,这是未定义的行为。
如果a 没有在其他任何地方定义,那么int a=1;将被视为a 的外部 定义(尽管在同一文件中定义)。所以它不是未定义的。
【讨论】:
是的,我认为这将导致(依赖于工具链的)行为。为什么?
编译器在翻译int a = ...; 之类的代码时生成一个(对于链接器)可见符号“a”。 extern int a; 行告诉编译器每个对 'a' 的引用都将由链接器解析。
这留下了编译器处理这种矛盾的两种可能方式: 1. 偶然(因为您只有一个名为“a”的可见符号)链接器将引用绑定到同一翻译单元的已创建符号“a”。 2.编译器忽略extern语句,直接绑定到本编译单元的a上。
必须将“内部”符号声明为静态 (static int a = ...;),然后我认为你会得到你的 UB。
【讨论】: