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
,并打印“1”x
- ,抱怨:“错误:之前声明为“static”的变量重新声明为“extern”
x
的先前声明,以下每个“if”子句的条件均为真,第一个用于第一个先前声明,第二个用于第二个先前声明:
- …如果先前声明指定内部或外部链接,则后面声明中标识符的链接与先前声明中指定的链接相同
- …如果先前的声明未指定任何链接,则标识符具有外部链接
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