【问题标题】:Inline function at -O0 causes link failure in clang [duplicate]-O0处的内联函数导致clang中的链接失败[重复]
【发布时间】:2015-05-28 20:24:15
【问题描述】:

我正在尝试在各种优化级别使用 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 987654332@.

【问题讨论】:

  • 尝试添加static。例如static inline int foo() { return 42; }
  • 是的,添加static 解决了-O0 的问题,但我问的是为什么它确实在更高的优化级别上编译。

标签: c optimization clang inline c99


【解决方案1】:

-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是什么:

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

这在草案 C99 标准部分 6.7.4 中进行了介绍函数说明符

任何具有内部链接的函数都可以是内联函数。对于具有外部功能的 链接,以下限制适用: 如果一个函数是用一个内联函数说明符声明的,那么它也应该在同一个翻译单元中定义。如果所有的 翻译单元中函数的文件范围声明包括内联函数 没有 extern 的说明符,则该翻译单元中的定义是内联的 定义。内联定义不为函数提供外部定义, 并且不禁止在另一个翻译单元中进行外部定义。内联定义 提供了外部定义的替代方案,翻译人员可以使用它来实现 在同一个翻译单元中对函数的任何调用。未指定是否调用 函数使用内联定义或外部定义。122)

这个网站对语言有很好的解释:The tricky inline specifier in C99

【讨论】:

  • 这正是 inline 函数所期望的。如前所述,它不会与-O0 内联(也未编译)。 See that one live
  • @Jongware 是的,我花了很多时间在 C++ 领域,我需要仔细阅读 C99 的这一部分。好的,TIL 一些新的东西。
  • 我认为您的“棘手的内联说明符”链接中的解决方案 #2 是错误的:如果在两个不同的 TU 中使用标头,则在标头中包含 extern inline void foo() { body } 会导致多个外部定义。正确的设置是在标题中包含 inline void foo() { body },并且在一个 TU 中包含 extern inline void foo();
  • @MattMcNabb 我认为该建议的意思是更接近clang docs 在第 3 条中所说的内容,但尚不清楚。
  • @ShafikYaghmour 同意目前尚不清楚。该要点还应该提到extern inline int add(); 就足够了,没有必要甚至不需要在其他地方重复函数体(或参数列表)。
猜你喜欢
  • 1970-01-01
  • 2013-06-24
  • 2019-05-06
  • 1970-01-01
  • 2014-09-27
  • 2012-01-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多