问题描述
第三个x
在其中应指什么:
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:
- 在Apple LLVM 9.1.0 clang-902-0.39.2中,
extern char x
的x
引用第一个x
,并打印"1". - GCC 8.2不接受该源文本.,抱怨道:错误:变量先前声明为'静态"重新声明为外部"".
- 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说:
C 2018 6.2.2 4 says:
由于有两个x
的在先声明,因此以下每个"if"子句的条件为true,第一个用于第一个在先声明,第二个用于第二个在先声明:
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:
- …如果在先声明指定内部或外部链接,则在后一个声明中标识符的链接与在先声明中指定的链接相同.
- …如果先前声明未指定任何链接,则标识符具有外部链接.
这里的Clang行为与使用第一个子句是一致的,因此第三个x
具有内部链接,并且与第一个x
引用相同的对象. GCC在这里的行为与使用第二个子句是一致的,因此第三个x
具有外部链接,并且与第一个x
具有内部链接冲突.
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.
C标准是否为我们提供了一种方法来解决其中的一种情况?
Does the C standard give us a way to resolve which of these should be the case?
推荐答案
第三个声明extern char x
应该基于C 2018 6.2.2 4声明具有外部链接的x
,它说:
The third declaration, extern char x
, should declare x
with external linkage, based on C 2018 6.2.2 4, which says:
在声明extern char x
处,x
的第一个声明不可见,因为它已被第二个声明隐藏.因此,它不符合该标识符的先前声明可见"的条件. x
的第二个声明是可见的,因此对于上一段而言,它是先前的声明".
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.
然后,最后一句话应该控制:先前的声明未指定任何链接(6.2.2 6,没有extern
的块范围标识符没有链接),因此第三个x具有外部链接.
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.
则违反了6.2.2 7,因为第一个x
具有内部链接,而第三个x
具有外部链接:
Then 6.2.2 7 is violated because the first x
has internal linkage and the third x
has external linkage:
由于没有违反语法规则或约束,因此标准不需要C实现来报告诊断.由于行为是不确定的,因此它可以执行任何操作,包括接受此代码并使第三个x
引用与第一个x
相同的对象.因此,在这方面,Clang和GCC的行为均未违反标准.但是,由于违反了6.2.2 7的要求,因此诊断可能是更可取的选择,而缺少该诊断程序可能会导致Clang的缺陷.
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.
(向 Paul Ogilvie 和用他们的评论告知了我对此的想法.)
(Credit to Paul Ogilvie and T.C. for informing my thinking on this with their comments.)
这篇关于对于带有extern的新声明,如何解决多个先前的声明?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!