在块范围内使用extern

时间:2014-04-29 14:42:16

标签: c++ c++11 language-lawyer extern

clang,gcc和VS2013都抱怨wmain()的重新定义,但我在标准中找不到任何不允许这样做的内容。

namespace N {
    extern int j;
    int j;
}

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

这些段落说明了在块范围内使用extern声明,但它们似乎不能证明错误消息的合理性:

§3.3.1/ 4

  

在单个声明性区域中给出一组声明,......

     

[注意:这些限制适用于声明区域   引入了一个名称,该名称不一定与该地区相同   声明发生的地方。特别是,   详细说明类型说明符(7.1.6.3)和朋友声明(11.3)   可能会在封闭中引入(可能不可见)名称   命名空间;这些限制适用于该地区。 当地外部   声明(3.5)可以在声明区域中引入名称   宣言出现的地方,也介绍一个(可能没有   可见的名称到一个封闭的命名空间;这些限制适用于   两个地区。 - 后注]

§3.3.2/ 10

  

[注意:朋友声明指的是函数或类   最近的封闭命名空间的成员,但他们没有介绍   该命名空间中的新名称(7.3.1.2)。函数声明在   使用extern说明符阻止范围和变量声明   块范围是指作为封闭成员的声明   命名空间,但它们不会在该范围中引入新名称。 -结束   注意]

2 个答案:

答案 0 :(得分:7)

我认为这主要由§3.5/ 6涵盖。

特别是:

  

在块作用域中声明的函数的名称和由块作用域extern声明声明的变量的名称具有链接。如果存在具有相同名称的链接的实体的可见声明并且键入,忽略在最内层封闭命名空间范围之外声明的实体,块范围声明声明该实体并接收先前声明的链接。如果存在多个这样的匹配实体,则该程序是不正确的。否则,如果未找到匹配的实体,则为块范围实体   接受外部联系。

因此,extern int w;声明了一个具有链接的w(在这种情况下,外部链接,因为此时没有匹配的实体可见)。

然后你尝试定义一个没有链接的本地w(§3.5/ 8)。

它在同一范围内提供了两个相同名称的声明,但具有不同的链接。这是§3.3.1/ 4所禁止的:

  

在单个声明性区域中给出一组声明,每个声明都指定相同的非限定名称,

     
      
  • 他们都应该引用同一个实体,或者全部引用功能和功能模板;或
  •   
  • 只有一个声明应声明一个不是typedef名称的类名或枚举名   其他声明都应引用相同的变量或枚举,或全部引用功能和功能模板;在这种情况下,隐藏类名或枚举名(3.3.10)。
  •   

既不引用函数,函数模板,类名或枚举名,也不适用这些“转义条款”。这两个声明必须引用同一个实体,该实体必须同时具有外部链接和无链接。由于这是不可能的,代码是不正确的。

答案 1 :(得分:0)

以下是我的解释:在§3.3.1/ 3中,标准说:

  

声明声明的名称被引入声明发生的范围,除了朋友说明符(11.3)的存在,详细类型说明符(7.1.6.3)的某些用法,以及使用 - 指令(7.3.4)改变了这种一般行为。

由于extern声明未列为异常,因此在块作用域中引入了名称,这就是当您尝试重新声明它时出现错误的原因。

您引用的段落

  

但他们没有在该范围内引入新名称。

这有点模棱两可,因为提到了块范围和命名空间范围。如果标准引用了块范围,那么标准就会自相矛盾,所以我假设命名空间范围是指。