clang,gcc和VS2013都抱怨w
中main()
的重新定义,但我在标准中找不到任何不允许这样做的内容。
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说明符阻止范围和变量声明 块范围是指作为封闭成员的声明 命名空间,但它们不会在该范围中引入新名称。 -结束 注意]
答案 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
声明未列为异常,因此在块作用域中引入了名称,这就是当您尝试重新声明它时出现错误的原因。
您引用的段落
但他们没有在该范围内引入新名称。
这有点模棱两可,因为提到了块范围和命名空间范围。如果标准引用了块范围,那么标准就会自相矛盾,所以我假设命名空间范围是指。