-O0处的内联函数导致clang中的链接失败

Jef*_*mes 3 c optimization inline c99 clang

我正在尝试使用各种优化级别的clang编译以下代码:

#include <stdio.h>

inline int foo() { return 42; }

int main() {
    printf("%d\n", foo());
}
Run Code Online (Sandbox Code Playgroud)

-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)
Run Code Online (Sandbox Code Playgroud)

Clang的内联兼容性-O0可以解释(和变通方法)的失败,但是无论优化级别如何,我都天真地期望这会失败.似乎一些优化已经启用了一些东西来阻止这种链接错误的发生,但我很好奇它们是什么样的优化,以及为什么它们似乎具有不同于单独使用的语义.-O1inline-O0

Sha*_*our 5

-O1和更大的他并没有叫这只是移动代码到功能main,我们可以通过查看此godbolt这说明ASM如下现场观看:

main:                                   # @main
  pushq %rax
  movl  $.L.str, %edi
  movl  $42, %esi
  xorl  %eax, %eax
  callq printf
  xorl  %eax, %eax
  popq  %rdx
  retq
Run Code Online (Sandbox Code Playgroud)

这是什么引用说:

[...]因为如果没有内联添加(例如,在没有优化的情况下进行编译),那么main将会有一个未解析的对其他定义的引用[...]

草案C99标准部分6.7.4 功能说明符包括:

具有内部链接的任何函数都可以是内联函数.对于具有外部链接的函数,以下限制适用:如果使用内联函数说明符声明函数,则它也应在同一转换单元中定义.如果转换单元中函数的所有文件范围声明都包含不带extern的内联函数说明符,则该转换单元中的定义是内联定义.内联定义不提供函数的外部定义,也不禁止另一个转换单元中的外部定义.内联定义提供了外部定义的替代,翻译器可以使用该定义在同一翻译单元中实现对该功能的任何调用.未指定对函数的调用是使用内联定义还是使用外部定义.222)

这个网站有很好的语言解释:C99中棘手的内联说明符