考虑以下示例:
extern void not_defined();
void f() {
not_defined();
}
int main() {}
如果我编译并链接上述程序,我会收到链接器错误 undefined reference to not_defined()
。 (https://godbolt.org/z/jPzscK7ja)
这是预期的,因为我使用 not_defined
进行 ODR .
但是,如果我做 f()
内联函数,程序可以正确编译和链接( https://godbolt.org/z/qEEob9ann ):
extern void not_defined();
// inline is added here
inline void f() {
not_defined();
}
int main() {}
这也适用于成员函数的内联定义(因为它们也是内联的?)( https://godbolt.org/z/xce3neofW ):
extern void not_defined();
struct C {
void f_member() {
not_defined();
}
void recurse() {
f_member();
};
};
inline void f_free_inline() {
not_defined();
}
// void f_free() {
// not_defined();
// }
int main() {
C c;
// f_free_inline();
}
如果我取消注释f_free
或f_free_inline()
在main()
它不再起作用了。这种效果似乎甚至是传递性的,因为 recurse
来电 f_member
,和f_member
来电 not_defined()
.
所以我的问题是,内联函数有什么特别之处使得这成为可能?
编辑:
如果内联函数位于模块的权限范围内(即使未导出),则此技巧将不再起作用:
export module mod_interface;
extern void not_defined();
export inline void f_module() {
not_defined();
}
以上将导致 not_defined
的链接器错误.
这很令人难过,因为我正在将库移植到模块中,突然得到了很多 undefined reference 。其中一些函数被包装在内联函数中。
最佳答案
标准不仅仅是对编译器行为的一组要求。这也是对程序员行为的一套要求。
如果 ODR 使用缺失符号 Y
的函数 X()
是 内联
或 ,GCC 的链接器不会提示static
函数,因为如果它具有本地链接并且可以忽略不计(如果它是内联的),则不可能从外部模块调用它们。
但是瞧!不管您是否能够编译并运行该程序,您的程序根据标准都是不正确的。仅在内联函数 X()
的情况下,一旦在任何编译单元中都没有找到对内联 X()
的引用,链接器就会对其进行优化。
如果它不是内联函数,它将保留到链接的最后阶段,并且将通过模块查找缺少的名称。编译器的实现是在排除未使用的 X()
之前对其进行搜索。其他一些编译器的行为可能有所不同。
这就是为什么它是“格式错误”的代码,但“不需要诊断”。通过某些实现方式可以进行诊断。有些实现会将这两种情况诊断为错误,有些则无法检测到您的欺骗。仅当您有多个编译单元时,某些实现才会检测到问题。
关于c++ - 为什么在内联函数内部调用的函数不需要定义?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71948111/