我正在尝试使用各种优化级别的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
及以上启用的某些优化正在做一些事情以防止发生此链接错误,但我很好奇它们是哪些优化以及为什么它们似乎具有与使用{{1}不同的语义单独在inline
。
答案 0 :(得分:5)
在-O1
及更高版本,它没有调用该函数,只是将代码移动到main
,我们可以通过使用显示asm的godbolt来看到这一点{{3} }:
main: # @main
pushq %rax
movl $.L.str, %edi
movl $42, %esi
xorl %eax, %eax
callq printf
xorl %eax, %eax
popq %rdx
retq
是哪个
[...]因为如果没有内联添加(例如,在没有优化的情况下编译时),那么main将有一个未解析的对其他定义的引用[...]
草案C99标准部分6.7.4
函数说明符:
任何具有内部链接的函数都可以是内联函数。用于外部功能 链接,以下限制适用:如果使用内联函数说明符声明函数,则它也应在同一个转换单元中定义。如果所有的 翻译单元中函数的文件范围声明包括内联函数 没有extern的说明符,那么该翻译单元中的定义是内联的 定义。内联定义不提供函数的外部定义, 并且不禁止在另一个翻译单元中使用外部定义。内联定义 提供了外部定义的替代方案,翻译人员可以使用该定义来实现 在同一翻译单元中对该功能的任何调用。没有具体说明是否打电话给 函数使用内联定义或外部定义.22)
此网站对该语言有一个很好的解释:reference says