[basic.link]/6
在块作用域中声明的函数的名称和由块作用域
extern声明声明的变量的名称具有链接.如果存在具有相同名称和类型的链接的实体的可见声明,忽略在最内部封闭命名空间范围之外声明的实体,则块范围声明声明该实体并接收先前声明的链接.如果存在多个这样的匹配实体,则该程序是不正确的.否则,如果未找到匹配的实体,则块范围实体将接收外部链接.[示例:Run Code Online (Sandbox Code Playgroud)static void f(); static int i = 0; // #1 void g() { extern void f(); // internal linkage int i; // #2 i has no linkage { extern void f(); // internal linkage extern int i; // #3 external linkage } }
i此程序中有三个对象.具有内部链接的对象由全局范围内的声明引入(第1行),具有自动存储持续时间的对象并且没有由第2行上的声明引入的链接,以及具有静态存储持续时间和由声明引入的外部链接的对象在第3行. - 末端的例子]
我对这一段有两点评论:
static int i = 0;全局范围内的声明在包含声明的块(#3)中不可见extern int i;.因此,我们只能说后一种宣言具有外部联系,即我们不能将其与宣言#1联系起来.static int i;被声明#3视为可见,则根据段落中的文本,块作用域声明声明相同的实体并接收前一声明的链接,即内部链接,而不是外部链接,如实施例中所述.我在这里错过了什么?
我使用g ++(7.1)和clang ++(xcode 9.0)编译了以下程序-std=c++11 -Wall并获得结果:
克++
0x10052c050
0x10052c040
0x10052c040
Run Code Online (Sandbox Code Playgroud)
铛++
0x108b74024
0x108b74018
0x108b74018
Run Code Online (Sandbox Code Playgroud)
这意味着extern int a[];和static int a[3];声明相同的实体并具有相同的链接(内部链接).
//a.cpp
#include <stdio.h>
int a[3];
void f()
{
printf("%p\n", (void*)a);
};
//b.cpp
extern void f();
static int a[3];
void g()
{
printf("%p\n", (void*)a);
extern int a[];
printf("%p\n", (void*)a);
}
int main(int argc, char* argv[])
{
f();
g();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
但是,在C++ 11 [3.9/6]中:
...数组对象的声明类型可能是一个未知大小的数组,因此在翻译单元的某一点不完整,稍后会完成; 这两个点的数组类型("T的未知边界数组"和"NT数组")是不同的类型....
int a[3];并且int a[];是不同的类型,
在C++ 11 [3.5/6]中:
如果与具有相同名称和类型关联实体的可见声明,忽略了最内层的命名空间范围之内声明的实体, …