内联是不是确定内部链接?
Posted
技术标签:
【中文标题】内联是不是确定内部链接?【英文标题】:Does inline determine internal linkage?内联是否确定内部链接? 【发布时间】:2019-05-28 20:05:53 【问题描述】:我正在尝试外部化一个内联函数。我认为它应该如何工作:
//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
添加到所有内容之前,a.cpp
中的f
有内部链接?
我正在使用 MSVC 2017 (v141) 和 /permissive-
和 /std:c++17
【问题讨论】:
提及您正在使用的编译器会有所帮助(标记它)extern inline void f(int)
看起来有点奇怪。您已经为一个被标记为在别处定义的函数给出了定义。
The definition of an inline function or variable (since C++17) must be present in the translation unit where it is accessed.
函数inline void f(int)
已经有外部链接并且必须在b.cpp
中定义。该功能已经具有外部链接。 static inline void f(int)
有内部。
@KamilCuk 这既是一个声明,也是一个定义。
@KamilCuk 扩展之前的内容:所有定义都是声明。
【参考方案1】:
我正在尝试外部化一个内联函数。
没有理由将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
。")。
该引用是正确的,但在它说 “内联函数的定义 [...] 必须存在于访问它的翻译单元中存在 [...]”。 您的示例在b.cpp
中声明了f
,但没有定义。如果您要从b.cpp
调用f
,则需要该翻译单元中的完整定义,如:
inline void f(int)
(这与存在于a.cpp
中的代码相同。)如果你去掉花括号,那么你有一个声明而不是一个定义,这使得从该翻译单元调用f
是非法的。
基本上,在头文件之外定义内联函数确实很痛苦,除非你给它内部链接。这是因为每个使用内联函数的源文件都需要自己的函数体副本,这意味着如果您更改函数,则需要在多个文件中进行更改。钱币。不要这样做。在头文件中定义每个 inline
函数。如果您认为您想在源文件中定义一个,您可能误解了“inline
”的含义。
“inline
”是什么意思?
就编译器而言,inline
关键字(几乎)没有任何意义。它只是函数定义上的一个标志,它被传播到目标代码中,以便 链接器 看到它。编译器像处理任何其他函数一样处理该函数。该函数可以正常调用,也可以内联调用——就像任何其他函数一样。
编译器可能对inline
标志执行某些操作的一种情况是,当函数被声明为inline
,但缺少定义时。这是一个可以在链接器接管之前捕获的错误。它没有必须被编译器捕获,但它可以。 (如果没有被编译器捕获,它将被链接器捕获。)
进入链接阶段。当链接器看到inline
标志时,它会暂停该函数的单一定义规则。链接器将期望在编译器优化后仍使用该函数的每个翻译单元中看到该函数的定义。它可以选择其中任何一个定义作为最终实现。因此,所有定义都必须匹配。
就是这样。 inline
关键字基本上意味着函数定义在头文件中。它告诉链接器在该定义出现在多个翻译单元中时不要抱怨,因为这是意料之中的。
回到这个问题,看起来意图是声明一个inline
函数,其定义只会出现在一个翻译单元中。换句话说,该函数将被标记为在多个翻译单元中定义,但定义将仅在一个翻译单元中。那里有点不一致,如果不是完全矛盾的话。
【讨论】:
“该函数可以正常调用,也可以内联调用它——就像任何其他函数一样。”。这并不完全正确。至少对于 Clang,内联说明符 - 当应用于函数时 - 会调整内联成本阈值并使其更有可能内联函数。以上是关于内联是不是确定内部链接?的主要内容,如果未能解决你的问题,请参考以下文章