gcc 无法在没有 -O2 的情况下内联函数

Osc*_*son 3 c optimization gcc inline gcc6

我最近遇到了在升级 debian 测试后编译一段代码的问题,得到了 gcc 6.2.1 编译器。我把它归结为这个简单的例子:

inline int func(void) {
    return 0;
}

int main (int argc, char **argv) {
    func();
}
Run Code Online (Sandbox Code Playgroud)

该代码不会与下面的编译:

gcc -o exec code.c # gcc 6.2.1

它失败了:

undefined reference to 'func'

我也在同一台主机上尝试过 gcc 4.8、4.9 和 5,但都失败了。如果我添加,它会编译:

gcc -o exec code.c -O2 # gcc 6.2.1

我真的很好奇为什么它与 -O2 标志一起工作,但不是没有,我希望这能工作?

Sum*_*ini 9

将“-O”选项添加到您的编译器命令中。内联仅在启用优化时打开。

C99 内联函数

默认情况下,Clang 以 GNU C11 模式构建 C 代码,因此它对 inline 关键字使用标准 C99 语义。这些语义与 GNU C89 模式中的语义不同,后者是 5.0 之前 GCC 版本中的默认模式。例如,考虑以下代码:

inline int add(int i, int j) { return i + j; }

int main() {
  int i = add(4, 5);
  return i;
}
Run Code Online (Sandbox Code Playgroud)

在 C99 中,内联意味着函数的定义仅用于内联,并且在程序的其他地方还有另一个定义(没有内联)。这意味着这个程序是不完整的,因为如果 add 没有被内联(例如,在没有优化的情况下编译时),那么 main 将有一个对其他定义的未解析引用。因此,我们会得到一个(正确的)链接时错误,如下所示:

Undefined symbols:
  "_add", referenced from:
      _main in cc-y1jXIr.o
Run Code Online (Sandbox Code Playgroud)

相比之下,GNU C89 模式(在旧版 GCC 中默认使用)是 C89 标准加上许多扩展。C89 没有内联关键字,但 GCC 将其识别为扩展并仅将其视为对优化器的提示。

有几种方法可以解决这个问题:

  1. 将 add 更改为静态内联函数。如果只有一个翻译单元需要使用该功能,这通常是正确的解决方案。静态内联函数始终在翻译单元内解析,因此您不必在程序的其他地方添加函数的非内联定义。
  2. 从 add 的这个定义中删除 inline 关键字。内联函数不需要 inline 关键字,也不保证它会被内联。一些编译器完全忽略它。Clang 将其视为来自程序员的温和建议。
  3. 在程序中的其他地方提供 add 的外部(非内联)定义。这两个定义必须是等价的!
  4. 通过将 -std=gnu89 添加到 Clang 选项集,以 GNU C89 方言进行编译。仅当程序源无法更改或程序还依赖于无法更改的其他特定于 C89 的行为时,才建议使用此选项。

所有这些仅适用于 C 代码;C++ 中 inline 的含义与其在 GNU89 或 C99 中的含义大不相同。