内联是否确定内部链接?

时间:2019-05-28 20:05:54

标签: c++ inline linkage

我正在尝试内联函数。我认为它应该如何工作:

//a.cpp
inline void f(int) {}
//b.cpp
extern void f(int);
int main() { f(4); }

但是出现链接错误。然后通过阅读this(“ 1”,必须在每个翻译单元中将其声明为inline”)。我尝试过的:

//a.cpp
inline void f(int) {}
//b.cpp
extern inline void f(int);
int main() { f(4); }

仍然出现链接错误。但是现在,尝试一些我不知道自己在做什么的事情:

//a.cpp
extern inline void f(int) {}
//b.cpp
extern inline void f(int);
int main() { f(4); }

有效。这里发生了什么事?在将extern添加到所有内容之前,f中的a.cpp具有内部链接吗?

我正在将MSVC 2017(v141)与/permissive-/std:c++17一起使用

1 个答案:

答案 0 :(得分:3)

  

我正在尝试内联函数。

没有理由将extern与函数一起使用。参见storage duration - linkage。函数默认具有外部链接;为了没有外部链接,需要做一些特殊的事情(即,将其放在匿名名称空间中或声明为static)。因此,内联函数的正常使用已经显示出外部链接,而无需使用extern关键字。

  

我认为它应该如何工作:

//a.cpp
inline void f(int) {}
//b.cpp
extern void f(int);
int main() { f(4); }
     

然后通过阅读this(“ 1),必须在每个翻译单元中将其声明为inline”)。

该参考文献是正确的,但要在其表示的地方稍加查找。“必须在内联函数[...]的访问单元中存在内联函数的定义[...]。 您的示例在f中有一个声明b.cpp,但没有定义。如果要从f调用b.cpp,则需要该翻译单元中的完整定义,如:

inline void f(int) {}

(这与a.cpp中存在的代码相同。)如果不使用花括号,则您有一个声明但没有定义,因此从该翻译中调用f是非法的单位。

基本上,除非在内部文件中指定内联函数,否则很难在头文件中定义内联函数。这是因为每个使用内联函数的源文件都需要自己的函数主体副本,这意味着如果更改函数,则需要在多个文件中进行更改。钱币。不要这样在头文件中定义每个inline函数。如果您想在源文件中定义一个,则可能会误解“ inline”的含义。


inline”是什么意思?

就编译器而言,inline关键字(几乎)没有任何意义。它只是函数定义上的一个标志,该标志被传播到目标代码中,以便 linker 看到它。编译器会像处理其他任何函数一样处理该函数。就像其他任何函数一样,该函数可以正常调用,也可以内联调用。

一种使用编译器可能会使用inline标志进行操作的情况是,使用了一个声明为inline的函数,但缺少定义。这是在链接程序接管之前可以捕获的错误。它没有会被编译器捕获,但是可以。 (如果没有被编译器捕获,它将由链接器捕获。)

进入链接阶段。链接器看到inline标志时,它将挂起该函数的一定义规则。链接器期望在编译器优化后仍在使用该功能的每个翻译单元中看到该功能的定义。它可以选择这些定义中的任何一个作为最终实现。因此,所有定义都必须匹配的原因。

就是这样。 inline关键字基本上意味着函数定义在头文件中。它告诉链接器该定义出现在多个翻译单元中时不要抱怨,因为这是预期的。

回到问题,看来是要声明一个inline函数,其定义只会出现在一个翻译单元中。换句话说,该功能将被标记为在多个翻译单元中定义,但该定义仅在一个中。那种不一致的地方,即使不是完全矛盾的。