如何将多个先前声明解析为带有 extern 的新声明?

2024-04-30

第三个应该是什么x参考:

#include <stdio.h>

static char x = '1';

int main(void)
{
    char x = '2';
    {
        extern char x;
        printf("%c\n", x);
    }
}

这发生在这个答案 https://stackoverflow.com/a/52875353/298225, and:

  • 在 Apple LLVM 9.1.0 clang-902-0.39.2 中,x of extern char x指的是第一个x,并打印“1”。
  • GCC 8.2 不接受此源文本。 https://godbolt.org/z/krEurT,抱怨:“错误:先前声明为‘static’的变量重新声明为‘extern’”。

C 2018 6.2.2 4 说:

对于使用存储类说明符声明的标识符extern在该标识符的先前声明可见的作用域中,如果先前的声明指定了内部或外部链接,则后面的声明中的标识符的链接与先前的声明中指定的链接相同。如果没有可见的先前声明,或者如果先前声明未指定链接,则该标识符具有外部链接。

由于之前有两个声明x,以下每个“if”子句的条件均为 true,第一个用于第一个先前声明,第二个用于第二个先前声明:

  • …如果先前的声明指定了内部或外部链接,则后面的声明中标识符的链接与先前声明中指定的链接相同。
  • …如果先前的声明指定没有链接,则该标识符具有外部链接。

Clang 在这里的行为与使用第一个子句一致,因此第三个子句x具有内部链接并引用与第一个对象相同的对象x。 GCC 在这里的行为与使用第二个子句一致,因此第三个子句x与第一个有外部联系并冲突x,具有内部链接。

C 标准是否为我们提供了一种方法来解决这些问题应该是哪种情况?


第三个声明,extern char x, 应声明x具有外部链接,基于 C 2018 6.2.2 4,其中表示:

对于使用存储类说明符声明的标识符extern在该标识符的先前声明可见的作用域中,如果先前的声明指定了内部或外部链接,则后面的声明中的标识符的链接与先前的声明中指定的链接相同。如果没有可见的先前声明,或者如果先前声明未指定链接,则该标识符具有外部链接。

在声明中extern char x,第一个声明x不可见,因为它已被第二个声明隐藏。因此,它不符合“该标识符的先前声明是可见的”。第二次声明x是可见的,因此它是上一段中的“事先声明”。

那么最后一句应该控制:先前的声明指定没有链接(6.2.2 6,没有块范围标识符extern没有链接),因此第三个 x 有外部链接。

那么 6.2.2 7 就被违反了,因为第一个x有内部联系和第三个x有外部链接:

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

由于没有违反语法规则或约束,因此标准不要求 C 实现报告诊断。由于行为未定义,因此它可以执行任何操作,包括接受此代码并创建第三个x引用与第一个对象相同的对象x。因此,Clang和GCC的行为在这方面都不违反标准。然而,由于违反了 6.2.2 7,因此诊断可能是首选,并且它的缺失可能被视为 Clang 的缺陷。

(归功于保罗·奥格尔维 https://stackoverflow.com/users/3100312/paul-ogilvie and T.C. https://stackoverflow.com/users/2756719/t-c通过他们的评论来告知我对此的想法。)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何将多个先前声明解析为带有 extern 的新声明? 的相关文章

随机推荐