第三个应该是什么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(使用前将#替换为@)