我正在尝试在各种优化级别使用 clang 编译以下代码:
#include <stdio.h>
inline int foo() { return 42; }
int main() {
printf("%d\n", foo());
}
在-O1
、-O2
、-O3
、-Os
处编译成功,但是使用 -O0
时失败:
$ clang -O0 -o main main.c
Undefined symbols for architecture x86_64:
"_foo", referenced from:
_main in main-8b9319.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
-O0
处的故障(和解决方法)可以用 Clang's inline compatibility 来解释,但是无论优化级别如何,我都会天真地期望它会失败。似乎在 -O1
及以上启用的一些优化正在做一些事情来防止发生此链接错误,但我很好奇它们是哪些优化以及为什么它们似乎具有与使用不同的语义inline
单独在 -O0
。
在 -O1
和更高版本中,它不会调用函数,它只是将代码移动到 main
中,我们可以通过使用 godbolt 看到这一点显示如下的 asm see it live :
main: # @main
pushq %rax
movl $.L.str, %edi
movl $42, %esi
xorl %eax, %eax
callq printf
xorl %eax, %eax
popq %rdx
retq
reference says 是什么:
[...]because if add isn't inlined (for example, when compiling without optimization), then main will have an unresolved reference to that other definition[...]
这包含在草案 C99 标准部分 6.7.4
函数说明符中:
Any function with internal linkage can be an inline function. For a function with external
linkage, the following restrictions apply: If a function is declared with an inline function specifier, then it shall also be defined in the same translation unit. If all of the
file scope declarations for a function in a translation unit include the inline function
specifier without extern, then the definition in that translation unit is an inline
definition. An inline definition does not provide an external definition for the function,
and does not forbid an external definition in another translation unit. An inline definition
provides an alternative to an external definition, which a translator may use to implement
any call to the function in the same translation unit. It is unspecified whether a call to the
function uses the inline definition or the external definition.122)
本站对语言有很好的解释:The tricky inline specifier in C99