【问题标题】:Use of extern in translation unit在翻译单元中使用 extern
【发布时间】:2013-01-24 10:58:30
【问题描述】:
extern int a;
int a = 1;

int main(void)
{
  return 0;
}

这是 UB 吗?标准在 6.2.2/7 中说

如果在一个翻译单元中,相同的标识符同时出现在内部和外部 链接,行为未定义。

【问题讨论】:

    标签: c extern linkage


    【解决方案1】:

    这是完全定义的行为。这就是编译器在包含头文件后进行预处理后得到的结果。

    你的困惑似乎来自:

    int a = 1;
    

    没有内部链接。在文件范围a 具有外部链接。如果添加了static 说明符,它将具有内部链接。

    【讨论】:

      【解决方案2】:

      默认链接externextern 说明符表示它可能在另一个翻译单元或同一个翻译单元中定义和初始化。 extern 声明的相对位置无关紧要,否则它们会有些危险。

      C99 TC2 §6.9.2/1

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

      下面是一个例子:

      int i1 = 1;  // definition, external linkage
      …
      extern int i1;  // refers to previous, whose linkage is external
      

      【讨论】:

      • C++11 标准真的与“C”问题相关吗?
      • @junix。没注意。我会在其他标准中查找它,但这是它们通常兼容的领域。
      【解决方案3】:

      答案是肯定的和否定的。

      如果a 在同一翻译单元的其他地方定义,那么是的,这是未定义的行为。

      如果a 没有在其他任何地方定义,那么int a=1;将被视为a外部 定义(尽管在同一文件中定义)。所以它不是未定义的。

      【讨论】:

        【解决方案4】:

        是的,我认为这将导致(依赖于工具链的)行为。为什么?

        编译器在翻译int a = ...; 之类的代码时生成一个(对于链接器)可见符号“a”。 extern int a; 行告诉编译器每个对 'a' 的引用都将由链接器解析。

        这留下了编译器处理这种矛盾的两种可能方式: 1. 偶然(因为您只有一个名为“a”的可见符号)链接器将引用绑定到同一翻译单元的已创建符号“a”。 2.编译器忽略extern语句,直接绑定到本编译单元的a上。

        必须将“内部”符号声明为静态 (static int a = ...;),然后我认为你会得到你的 UB。

        【讨论】:

        • 编译器做不到那么贪婪。翻译 TU 时使用从头到尾解析的内部参考,然后将它们合并。
        • @Potatoswatter 当然编译器可以做到这一点。尽管您可能是对的,但正确的实现将链接所有出现的 'a' extern 并让链接器完成这项工作。
        猜你喜欢
        • 1970-01-01
        • 2011-11-01
        • 1970-01-01
        • 2012-09-09
        • 1970-01-01
        • 2012-01-10
        • 2021-02-24
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多