如何将多个先前声明解析为带有 extern 的新声明?

发布于 2025-01-20 10:00:29 字数 1206 浏览 0 评论 0原文

第三x应该参考以下内容:

#include <stdio.h>

static char x = '1';

int main(void)
{
    char x = '2';
    {
        extern char x;
        printf("%c\n", x);
    }
}

此答案和:

  • in Apple llvm 9.1.0 clang-902-0.39.2,x extern char x打印。
  • gcc 8.2不接受此源文本。,抱怨:“错误:可变先前声明为'static'静态'redeclared “外部””。

C 2018 6.2.2 4说:

对于用存储级规范符声明的标识符 extern 在该范围中,如果先前的声明指定了内部或外部链接,则可以看到该标识符的先前声明,即标识符的链接在后来的声明中,声明与先前声明中指定的链接相同。如果没有可见事先声明,或者先前的声明没有指定链接,则标识符具有外部链接。

由于x有两个先前的声明,因此以下每个“如果”条款都是True的条件,第一个条款是第一个先前声明的第一个条款,第二个条款是第二个先前的声明:

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

Clang的行为与使用第一个子句是一致的,因此第三个X具有内部链接,并指的是与第一个x相同的对象。 GCC的行为与使用第二子句是一致的,因此第三个X具有外部链接,并且与具有内部链接的第一个X冲突。

C标准是否可以使我们有一种解决应有的方法?

What should the third x refer to in:

#include <stdio.h>

static char x = '1';

int main(void)
{
    char x = '2';
    {
        extern char x;
        printf("%c\n", x);
    }
}

This arose in this answer, and:

  • In Apple LLVM 9.1.0 clang-902-0.39.2, the x of extern char x refers to the first x, and “1” is printed.
  • GCC 8.2 does not accept this source text., complaining: “error: variable previously declared 'static' redeclared 'extern'”.

C 2018 6.2.2 4 says:

For an identifier declared with the storage-class specifier extern in a scope in which a prior declaration of that identifier is visible, if the prior declaration specifies internal or external linkage, the linkage of the identifier at the later declaration is the same as the linkage specified at the prior declaration. If no prior declaration is visible, or if the prior declaration specifies no linkage, then the identifier has external linkage.

Since there are two prior declarations of x, the condition of each of the following “if” clauses is true, the first for the first prior declaration, and the second for the second prior declaration:

  • … if the prior declaration specifies internal or external linkage, the linkage of the identifier at the later declaration is the same as the linkage specified at the prior declaration.
  • … if the prior declaration specifies no linkage, then the identifier has external linkage.

Clang’s behavior here is consistent with using the first clause, so that the third x has internal linkage and refers to the same object as the first x. GCC’s behavior here is consistent with using the second clause, so that the third x has external linkage and conflicts with the first x, which has internal linkage.

Does the C standard give us a way to resolve which of these should be the case?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

白色秋天 2025-01-27 10:00:29

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

对于用存储级规范符声明的标识符 extern 在该范围中,如果先前的声明指定了内部或外部链接,则可以看到该标识符的先前声明,即标识符的链接在后来的声明中,声明与先前声明中指定的链接相同。如果没有可见事先声明,或者先前的声明没有指定链接,则标识符具有外部链接。


在声明外部char x上,x的第一个声明不可见,因为第二个声明已隐藏。因此,它没有资格“可见该标识符的先前声明”。可见x的第二个声明,因此,就上述段落而言,它是“先前的声明”。

然后最后一个句子应控制:先前的声明指定没有链接(6.2.2 6,一个没有extern没有链接的块scope标识符),因此第三个X具有外部链接。

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

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

由于没有违反语法规则或约束,因此标准不需要C实施诊断。由于该行为是未定义的,因此它可能会做任何事情,包括接受此代码,并制作第三个x请参阅第一个x的对象。因此,Clang和GCC的行为均未违反这方面的标准。但是,由于违反了6.2.2 7,因此可能会首选诊断,并且它的缺席可能是Clang的缺陷。

(信用 Paul Ogilvie TC 用他们的评论来告知我对此的想法。)

The third declaration, extern char x, should declare x with external linkage, based on C 2018 6.2.2 4, which says:

For an identifier declared with the storage-class specifier extern in a scope in which a prior declaration of that identifier is visible, if the prior declaration specifies internal or external linkage, the linkage of the identifier at the later declaration is the same as the linkage specified at the prior declaration. If no prior declaration is visible, or if the prior declaration specifies no linkage, then the identifier has external linkage.

At the declaration extern char x, the first declaration of x is not visible, as it has been hidden by the second declaration. Therefore, it does not qualify for “a prior declaration of that identifier is visible.” The second declaration of x is visible, so it is a “prior declaration” for the purposes of the above paragraph.

Then the last sentence should control: The prior declaration specifies no linkage (6.2.2 6, a block-scope identifier without extern has no linkage), so the third x has external linkage.

Then 6.2.2 7 is violated because the first x has internal linkage and the third x has external linkage:

If, within a translation unit, the same identifier appears with both internal and external linkage, the behavior is undefined.

Since no syntax rule or constraint is violated, the C implementation is not required by the standard to report a diagnostic. Since the behavior is undefined, it may do anything, including accept this code and make the third x refer to the same object as the first x. Therefore, neither Clang nor GCC’s behaviors violate the standard in this regard. However, since 6.2.2 7 is violated, a diagnostic may be preferred, and its absence could be consider a defect of Clang.

(Credit to Paul Ogilvie and T.C. for informing my thinking on this with their comments.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文