C 如何使用extern为新声明解析多个先前声明?

C 如何使用extern为新声明解析多个先前声明?,c,language-lawyer,C,Language Lawyer,第三个x应该指什么: #include <stdio.h> static char x = '1'; int main(void) { char x = '2'; { extern char x; printf("%c\n", x); } } #包括 静态字符x='1'; 内部主(空) { 字符x='2'; { 外部字符x; printf(“%c\n”,x); } } 这发生在,并且: 在Apple LLVM 9.1.

第三个
x
应该指什么:

#include <stdio.h>

static char x = '1';

int main(void)
{
    char x = '2';
    {
        extern char x;
        printf("%c\n", x);
    }
}
#包括
静态字符x='1';
内部主(空)
{
字符x='2';
{
外部字符x;
printf(“%c\n”,x);
}
}
这发生在,并且:

  • 在Apple LLVM 9.1.0 clang-902-0.39.2中,
    extern char x
    x
    表示第一个
    x
    ,并打印“1”
  • ,抱怨:“错误:之前声明为“static”的变量重新声明为“extern”
C 2018第6.2.2 4节规定:

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

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

  • …如果先前声明指定内部或外部链接,则后面声明中标识符的链接与先前声明中指定的链接相同
  • …如果先前的声明未指定任何链接,则标识符具有外部链接
Clang在这里的行为与使用第一个子句一致,因此第三个
x
具有内部链接,并引用与第一个
x
相同的对象。GCC在这里的行为与使用第二个子句一致,因此第三个
x
具有外部链接,并与第一个
x
冲突,后者具有内部链接


C标准是否为我们提供了解决哪种情况的方法?

第三个声明,
extern char x
,应根据C 2018 6.2.2 4,声明具有外部链接的
x
,其中说明:

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

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

然后最后一句应该控制:前面的声明指定没有链接(6.2.26,没有
extern
的块范围标识符没有链接),因此第三个x具有外部链接

然后违反6.2.2 7,因为第一个
x
具有内部链接,第三个
x
具有外部链接:

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

由于没有违反语法规则或约束,因此标准不要求C实现报告诊断。由于行为未定义,它可以执行任何操作,包括接受此代码并使第三个
x
引用与第一个
x
相同的对象。因此,Clang和GCC的行为均未违反这方面的标准。然而,由于违反了2.2.2 7,诊断可能是首选的,并且它的缺失可以被认为是Clang的缺陷。
(感谢并通过他们的评论告知了我的想法。)

第三个声明,
extern char x
,应根据C 2018 6.2.2 4,声明具有外部链接的
x
,其中规定:

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

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

然后最后一句应该控制:前面的声明指定没有链接(6.2.26,没有
extern
的块范围标识符没有链接),因此第三个x具有外部链接

然后违反6.2.2 7,因为第一个
x
具有内部链接,第三个
x
具有外部链接:

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

由于没有违反语法规则或约束,因此标准不要求C实现报告诊断。由于行为未定义,它可以执行任何操作,包括接受此代码并使第三个
x
引用与第一个
x
相同的对象。因此,Clang和GCC的行为均未违反这方面的标准。H