c++ - 内联是否确定内部链接?
问题描述
我正在尝试 extern 一个内联函数。我认为它应该如何工作:
//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
一切之前,f
有a.cpp
没有内部联系?
我正在使用 MSVC 2017 (v141)/permissive-
和/std:c++17
解决方案
我正在尝试 extern 一个内联函数。
没有理由使用extern
函数。请参阅存储期限 - 关联。函数默认有外部联动;为了没有外部链接,需要做一些特殊的事情(即把它放在匿名命名空间中或声明它static
)。因此,内联函数的正常使用已经展示了不需要extern
关键字的外部链接。
我认为它应该如何工作:
//a.cpp inline void f(int) {} //b.cpp extern void f(int); int main() { f(4); }
然后通过阅读这个(“ 1)它必须
inline
在每个翻译单元中声明。 ”)。
该引用是正确的,但在它说“内联函数的定义[...]必须存在于访问它的翻译单元中[...]”的地方再多看一点。您的示例具有f
in声明b.cpp
,但没有定义。如果您要调用f
from b.cpp
,则需要该翻译单元中的完整定义,如下所示:
inline void f(int) {}
(这与 . 中存在的代码相同a.cpp
。)如果您去掉花括号,那么您有一个声明但没有定义,因此f
从该翻译单元调用是非法的。
基本上,在头文件之外定义内联函数是一件很痛苦的事情,除非你给它内部链接。这是因为每个使用内联函数的源文件都需要自己的函数体副本,这意味着如果您更改函数,则需要在多个文件中进行更改。钱币。不要这样做。inline
在头文件中定义每个函数。如果你认为你想在源文件中定义一个,你可能误解了“ inline
”的意思。
“ inline
”是什么意思?
就编译器而言,inline
关键字(几乎)没有任何意义。它只是函数定义上的一个标志,它被传播到目标代码中,以便链接器看到它。编译器像处理任何其他函数一样处理该函数。该函数可以正常调用,也可以内联调用它——就像任何其他函数一样。
编译器可能对标志做某事的一种情况inline
是,当一个函数被声明时inline
,被使用,但缺少定义。这是一个可以在链接器接管之前捕获的错误。它不必被编译器捕获,但它可以。(如果没有被编译器捕获,它将被链接器捕获。)
进入链接阶段。当链接器看到该inline
标志时,它会暂停该函数的单一定义规则。链接器将期望在编译器优化后仍使用该函数的每个翻译单元中看到该函数的定义。它可以选择其中任何一个定义作为最终实现。因此,所有定义必须匹配的原因。
就是这样。inline
关键字基本上意味着函数定义在头文件中。当该定义出现在多个翻译单元中时,它告诉链接器不要抱怨,因为这是意料之中的。
回到这个问题,看起来意图是声明一个inline
函数,其定义只会出现在一个翻译单元中。换句话说,该函数将被标记为在多个翻译单元中定义,但定义将仅在一个翻译单元中。那里有点不一致,如果不是完全矛盾的话。
推荐阅读
- c - 以相反的顺序打印字符串数组中的字符串
- python - 有没有办法在 Python 中创建参数化类型别名?
- jsf - 我正在尝试将一些贬义的代码 .createValueBinding 带到推荐代码更新中
- javascript - 反转时简单滑块正确添加类
- c# - UWP 从 TemplateSelector 更改为用户控件不再显示绑定
- java - Minecraft Player On World 加入活动
- django - 在Django中创建实例时使用类方法修改模型?
- python - 我的脚本或 XML 文件有问题吗?我正在使用 ElementTree 试图获取子属性
- python - python 与 python:alpine docker 镜像的兼容性如何?
- statistics - 比率校正