如何将多个先前声明解析为带有 extern 的新声明?
第三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
ofextern char x
refers to the firstx
, 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
第三个声明
extern char x
,应根据C 2018 6.2.2 4的外部链接声明x
,它说:在声明
外部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 declarex
with external linkage, based on C 2018 6.2.2 4, which says:At the declaration
extern char x
, the first declaration ofx
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 ofx
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 thirdx
has external linkage: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 firstx
. 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.)