C语言 如何解决与 extern 的新声明的多个先前声明?



第三个x应该指的是什么:

#include <stdio.h>
static char x = '1';
int main(void)
{
char x = '2';
{
extern char x;
printf("%cn", x);
}
}

这出现在这个答案中,并且:

  • 在 Apple LLVM 9.1.0 clang-902-0.39.2 中,extern char xx是指第一个x,并打印"1"。
  • GCC 8.2不接受此源文本,抱怨:"错误:先前声明为'静态'的变量重新声明为'extern'"。

C 2018 6.2.2 4 说:

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

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

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

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 的缺陷。

(感谢Paul Ogilvie和T.C.用他们的评论告知我对此的想法。

最新更新