【发布时间】:2017-02-01 11:42:53
【问题描述】:
来自C++17 Standard Draft§ 3.5.6:
块作用域中声明的函数名和块作用域extern声明的变量名 声明有联系。 如果存在具有相同名称的链接的实体的可见声明,并且 类型,忽略在最里面的封闭命名空间范围之外声明的实体,块范围声明 声明同一个实体并接收前一个声明的链接。如果有不止一个这样的 匹配实体,程序格式错误。否则,如果没有找到匹配的实体,则块范围实体 接收外部链接
另外在标准中提供了一个例子:
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
}
}
第三个函数声明extern void f()是否接收:
-
external链接(由于前面的extern void f()声明) -
internal链接(因为上面块作用域中f()的第二个声明接收来自::全局命名空间中f()声明的内部链接) - 或者它是不正确的,因为有多个这样的匹配 实体”?
编辑
main.cpp
#include <iostream>
extern void g();
void f() { std::cout << "main f() called" << std::endl; }
int main(){
g();
return 0;
}
test.cpp:
#include <iostream>
static void f() { std::cout << " test f() called" << std::endl; }
void g() {
extern void f();
{
extern void f();
f();
}
}
g() 在main.cpp 的main() 函数中被调用。
用gcc 5.4.0编译
g++ -std=c++14 -Wall main.cpp test.cpp
打印:
主 f() 调用
因此,gcc 显然将来自 g() 内的 f() 调用与 external 链接(调用 main.cpp 文件中提供的定义)。标准示例中的注释是错误的(#3 的函数声明没有内部链接)或者是来自gcc 的编译器错误。
【问题讨论】:
-
“忽略在最里面的封闭 namespace 范围之外声明的实体”。关键词是“命名空间”。示例中的所有标识符都在同一个命名空间中。
-
@AlexP 为什么来自
#3的变量i然后具有external链接而不是static链接,如#1中声明的那样? -
"在这个程序中有三个名为i的对象。在全局范围内(第1行)声明引入的具有内部链接的对象,具有自动存储时长的对象第 2 行的声明没有引入链接,并且第 3 行的声明引入了具有静态存储持续时间和外部链接的对象。”请参阅第 3.5.9 节,为什么
extern int i与static int i不同 i。 -
@AlexP 好吧,我明白了。有点棘手。因此,所有三个
i都表示三个不同的变量,所有f()都表示同一个函数?用g++ 5.4.0编译它为变量提供了正确的行为,但是对上面#3的函数f()的调用调用了在其他翻译单元中提供的定义。是来自gcc的错误还是最近草稿中的定义发生了变化? -
@SebTu:C++11 的草案 n3337 中的定义已经相同
标签: c++ language-lawyer iso c++17 linkage