内联是否决定内部链接?

Does inline determine internal linkage?

本文关键字:链接 内部 决定 是否      更新时间:2023-10-16

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

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

但是得到链接错误。然后通过阅读此内容(">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之前,a.cppf有内部联系吗?

我正在使用 MSVC 2017 (v141) 和/permissive-/std:c++17

我正在尝试外联函数。

没有理由将extern与函数一起使用。请参阅存储持续时间 - 链接。函数默认具有外部链接;为了没有外部链接,需要做一些特殊的事情(即将其放在匿名命名空间中或将其声明为static)。因此,内联函数的正常使用已经表现出外部链接,不需要extern关键字。

我认为它应该如何工作:

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

然后通过阅读此内容(">1)必须在每个翻译单元中声明inline

该引用是正确的,但是在它说"内联函数的定义[...]必须存在于访问它的翻译单元中 [...]。您的示例在b.cpp中声明了f,但没有定义。如果要从b.cpp调用f,则需要该翻译单元中的完整定义,如下所示:

inline void f(int) {}

(这与a.cpp中存在的代码相同。如果您省略了大括号,那么您有一个声明,但没有一个定义,这使得从该翻译单元调用f是非法的。

基本上,在头文件之外定义内联函数真的很痛苦,除非你给它内部链接。这是因为使用内联函数的每个源文件都需要自己的函数体副本,这意味着如果更改函数,则需要在多个文件中进行更改。哎呀。别这样。在头文件中定义每个inline函数。如果你认为你想在源文件中定义一个,你可能会误解"inline"的意思。


"inline"是什么意思?

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

编译器可能会使用inline标志执行某些操作的一种情况是,当函数被声明为inline时,使用了,但缺少定义。这是可以在链接器接管之前捕获的错误。它不必被编译器捕获,但可以。(如果未被编译器捕获,则链接器将捕获它。

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

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

回到问题,看起来意图是声明一个inline函数,其定义将只出现在一个翻译单元中。换句话说,该函数将被标记为在多个翻译单元中定义,但定义将仅在一个翻译单元中。那里有点不一致,如果不是完全矛盾的话。