为什么在内联函数中调用的函数不需要定义?
考虑以下示例:
extern void not_defined();
void f() {
not_defined();
}
int main() {}
如果我要编译并链接上述程序,则会获得链接器错误undefined引用到not_defined()
。 https://godbolt.org/z/jpzsck7ja )
( 代码> not_defined 。
但是,如果我制作f()
inline函数,则程序正确编译和链接( https://godbolt.org/z/qeeob9ann ):
extern void not_defined();
// inline is added here
inline void f() {
not_defined();
}
int main() {}
这也适用于成员函数的内联定义(因为它们也是内联的?) xce3neofw“ rel =” nofollow noreferrer”> 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();
}
)在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 。
这很可悲,因为我正在将图书馆移植到模块上,并突然得到了很多不确定的参考文献。其中一些功能包裹在内联函数中。
Consider the following example:
extern void not_defined();
void f() {
not_defined();
}
int main() {}
If I were to compile and link the above program, I get a linker error undefined reference to not_defined()
. (https://godbolt.org/z/jPzscK7ja)
This is expected because I am ODR using not_defined
.
However, if I make f()
a inline function, the program compiles and links correctly (https://godbolt.org/z/qEEob9ann):
extern void not_defined();
// inline is added here
inline void f() {
not_defined();
}
int main() {}
This also works for inline definitions of member functions (since they are also inline?) (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();
}
If I were to uncomment f_free
or f_free_inline()
in main()
it no longer works . This effects seem to be even transitive, since recurse
calls f_member
, and f_member
calls not_defined()
.
So my questions is, what's special about inline functions that makes this possible?
EDIT:
This trick cease to work if the inline function is inside the purview of a module (even if it is not exported):
export module mod_interface;
extern void not_defined();
export inline void f_module() {
not_defined();
}
The above would result in a linker error for not_defined
.
This is sad because I am porting a library to modules and suddenly got a lot of undefined references. Some of those functions in it were wrapped inside inline functions.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
标准不仅是编译器行为的设定要求。这也是对程序员行为的一系列要求。
GCC的链接器如果函数
x()
odr使用了丢失的符号y
是inline
或static
代码>函数,因为如果它具有本地链接并且可以忽略不计,则不可能从外部模块中调用它们。但是瞧!忽略了您能够编译和运行此程序的事实,根据标准,您的程序形成不佳。只有在Inline函数
x()
链接器中,只要在任何编译单元中找到对InlineX()
的引用后,链接器才能将其优化。如果不是内联功能,它将一直持续到链接的最后阶段,而丢失的名称将通过模块查找。编译器的实现使其在排除未使用
x()
之前将进行搜索。其他一些编译器的行为可能会有所不同。这就是为什么它是“不良”代码,但“不需要诊断”。通过某些实现,可以进行诊断。有些实现将诊断出这两种情况是错误,而有些则无法检测到您的欺骗。某些实现只有在您拥有多个编译单元时才能检测到问题。
Standard is not only a set requirements for compiler behaviour. It's also a set of requirements to programmer's behaviour.
GCC's linker wouldn't complain if a function
X()
that ODR-used a missing symbolY
isinline
orstatic
function, as there is no possibility that they would be called from outside module if it has local linkage and negligible, if it was inline.But lo! Disregard the fact that you're able to compile and run this program, your program is ill-formed according to standard. Only in case of inline function
X()
linker would optimize it out as soon as it didn't found a reference to inlineX()
in any of compile units.If it's not inline function, it would stay until final stage of linking and the missing name will be looked up through modules. Implementation of your compiler is such that it would be searched for before excluding unused
X()
. Some other compiler may behave differently.That's why it's "ill-formed" code, but "no diagnostic required". Diagnostic is possible with certain implementations. Some implementations will diagnose both cases as an error and some are unable to detect your deception. Some implementations will detect the problem only if you had more than one compile unit.