简体   繁体   English

在块范围内使用extern

[英]Use of extern in block scope

clang, gcc and VS2013 all complain about redefinition of w in main() , but I couldn't find in the Standard anything disallowing this. clang,gcc和VS2013都抱怨在main()重新定义w ,但我在标准中找不到任何禁止它的东西。

namespace N {
    extern int j;
    int j;
}

int main()
{
    extern int w;
    int w;
}

These paragraphs say something about the use of an extern declaration in block scope, but they don't seem to justify the error message: 这些段落说明了在块作用域中使用extern声明,但它们似乎不能证明错误消息的合理性:

§3.3.1/4 §3.3.1/ 4

Given a set of declarations in a single declarative region, ... 给定一个声明区域中的一组声明,......

[ Note: These restrictions apply to the declarative region into which a name is introduced, which is not necessarily the same as the region in which the declaration occurs. [注意:这些限制适用于引入名称的声明性区域,该名称不一定与声明发生的区域相同。 In particular, elaborated-type-specifiers (7.1.6.3) and friend declarations (11.3) may introduce a (possibly not visible) name into an enclosing namespace; 特别是,详细类型说明符(7.1.6.3)和友元声明(11.3)可能会将一个(可能不可见)名称引入封闭的名称空间中; these restrictions apply to that region. 这些限制适用于该地区。 Local extern declarations (3.5) may introduce a name into the declarative region where the declaration appears and also introduce a (possibly not visible) name into an enclosing namespace ; 本地extern声明(3.5)可能会在声明出现的声明区域中引入一个名称,并在一个封闭的命名空间中引入一个(可能不可见)名称 ; these restrictions apply to both regions. 这些限制适用于这两个地区。 —end note ] - 尾注]

§3.3.2/10 §3.3.2/ 10

[ Note: Friend declarations refer to functions or classes that are members of the nearest enclosing namespace, but they do not introduce new names into that namespace (7.3.1.2). [注意:Friend声明引用的函数或类是最近的封闭命名空间的成员,但它们不会在该命名空间中引入新名称(7.3.1.2)。 Function declarations at block scope and variable declarations with the extern specifier at block scope refer to declarations that are members of an enclosing namespace, but they do not introduce new names into that scope . 块作用域中的函数声明和使用块作用域中的extern说明符的变量声明引用作为封闭命名空间成员的声明,但它们不会在该作用域中引入新名称 —end note ] - 尾注]

I believe this is mostly covered by §3.5/6. 我认为这主要由§3.5/ 6涵盖。

In particular: 特别是:

The name of a function declared in block scope and the name of a variable declared by a block scope extern declaration have linkage. 在块作用域中声明的函数的名称和由块作用域extern声明声明的变量的名称具有链接。 If there is a visible declaration of an entity with linkage having the same name and type, ignoring entities declared outside the innermost enclosing namespace scope, the block scope declaration declares that same entity and receives the linkage of the previous declaration. 如果存在具有相同名称和类型的链接的实体的可见声明,忽略在最内部封闭命名空间范围之外声明的实体,则块范围声明声明该实体并接收先前声明的链接。 If there is more than one such matching entity, the program is ill-formed. 如果存在多个这样的匹配实体,则该程序是不正确的。 Otherwise, if no matching entity is found, the block scope entity receives external linkage. 否则,如果未找到匹配的实体,则块范围实体接收外部链接。

So, the extern int w; 所以, extern int w; declares a w that has linkage (external linkage, in this case, since no matching entity is visible at that point). 声明一个具有链接的w (外部链接,在这种情况下,因为此时没有匹配的实体可见)。

Then you attempt to define a local w which has no linkage (by §3.5/8). 然后你尝试定义一个没有链接的本地w (§3.5/ 8)。

That gives two declarations of the same name at the same scope, but with different linkages. 这在相同的范围内给出了两个相同名称的声明,但具有不同的链接。 That's prohibited by §3.3.1/4: 这是§3.3.1/ 4所禁止的:

Given a set of declarations in a single declarative region, each of which specifies the same unqualified name, 给定一个声明区域中的一组声明,每个声明区域指定相同的非限定名称,

  • they shall all refer to the same entity, or all refer to functions and function templates; 它们都应指同一实体,或全部指功能和功能模板; or 要么
  • exactly one declaration shall declare a class name or enumeration name that is not a typedef name and the other declarations shall all refer to the same variable or enumerator, or all refer to functions and function templates; 正好一个声明应声明一个不是typedef名称的类名或枚举名,其他声明都应引用相同的变量或枚举,或者全部引用函数和函数模板; in this case the class name or enumeration name is hidden (3.3.10). 在这种情况下,隐藏类名或枚举名(3.3.10)。

Neither refers to a function, function template, class name, or enumeration name, so none of these "escape clauses" applies. 两者都没有引用函数,函数模板,类名或枚举名,因此这些“转义子句”都不适用。 The two declarations must refer to the same entity, which must have both external linkage and no linkage. 这两个声明必须引用同一个实体,该实体必须同时具有外部链接和无链接。 Since that's impossible, the code is ill-formed. 由于这是不可能的,代码是不正确的。

Here is my interpretation: In §3.3.1/3 the standard says: 以下是我的解释:在§3.3.1/ 3中,标准说:

The names declared by a declaration are introduced into the scope in which the declaration occurs, except that the presence of a friend specifier (11.3), certain uses of the elaborated-type-specifier (7.1.6.3), and using-directives (7.3.4) alter this general behavior. 声明声明的名称被引入声明发生的范围,除了友元说明符(11.3)的存在,详细类型说明符(7.1.6.3)的某些用法和使用指令(7.3) .4)改变这种一般行为。

As extern declarations are not listed as exception, the name is introduced in the block scope, which is why you get the error when you try to redeclare it. 由于extern声明未列为异常,因此在块作用域中引入了该名称,这就是您尝试重新声明它时出现错误的原因。

The paragraph you quoted says 你引用的段落说

but they do not introduce new names into that scope. 但他们没有在该范围内引入新名称。

which is a bit ambiguous, as both block scope and namespace scope are mentioned. 这有点模棱两可,因为提到了块范围和命名空间范围。 The standard would contradict itself if it referred to block scope, so I assume that namespace scope is meant. 如果标准引用了块范围,那么标准就会自相矛盾,因此我假设命名空间范围是指。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM