【发布时间】:2019-03-23 09:46:09
【问题描述】:
第三个x应该指什么:
#include <stdio.h>
static char x = '1';
int main(void)
{
char x = '2';
{
extern char x;
printf("%c\n", x);
}
}
这发生在this answer,并且:
- 在Apple LLVM 9.1.0 clang-902-0.39.2 中,
extern char x的x指的是第一个x,并且打印了“1”。 - GCC 8.2 does not accept this source text.,抱怨:“错误:以前声明的变量 'static' 重新声明了 'extern'”。
C 2018 6.2.2 4 说:
对于使用存储类说明符extern声明的标识符,在该标识符的先前声明可见的范围内,如果先前声明指定内部或外部链接,则标识符的链接在后面的声明中与前面声明中指定的链接相同。如果前面的声明不可见,或者前面的声明没有指定链接,则标识符具有外部链接。
由于x 有两个先前声明,以下每个“if”子句的条件都为真,第一个用于第一个先前声明,第二个用于第二个先前声明:
- …如果前面的声明指定了内部或外部链接,则后面声明的标识符的链接与前面声明的链接相同。
- …如果前面的声明没有指定链接,则标识符有外部链接。
Clang 在这里的行为与使用第一个子句一致,因此第三个x 具有内部链接,并与第一个x 引用相同的对象。 GCC在这里的行为与使用第二个子句一致,因此第三个x具有外部链接,并与第一个x冲突,后者具有内部链接。
C 标准是否为我们提供了一种解决问题的方法?
【问题讨论】:
-
我认为您没有引用的 C11 注释 31 可能是相关的。
For an identifier declared with the storage-class specifier extern in a scope in which a prior declaration of that identifier is visible,31)其中注释 31 说31) As specified in 6.2.1, the later declaration might hide the prior declaration.这是这里的情况。 6.2.1是正常范围规则。在这种情况下,extern应该引用没有链接的局部变量。 -
@Lundin - 我认为这就是答案,你应该在这样的地方发帖。问题的症结似乎是
x在文件范围内的可见性。 -
@Lundin - 注意不是,但 6.2.1p4 中的最后一句话是。 “在内部范围内,标识符指定在内部范围内声明的实体;在外部范围内声明的实体在内部范围内是隐藏的(不可见)。”
-
我将添加 p7 然后声明未定义的行为。所以clang在技术上并没有错……
标签: c language-lawyer