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

gcc fails to inline functions without -O2

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

inline int func(void) {
    return 0;
}

int main (int argc, char **argv) {
    func();
}

该代码编译如下:

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 标志一起工作但没有,我希望它能工作?

为您的编译器命令添加“-O”选项。仅当启用优化时才启用内联。

C99 内联函数

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

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

int main() {
  int i = add(4, 5);
  return i;
}

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

Undefined symbols:
  "_add", referenced from:
      _main in cc-y1jXIr.o

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

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

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

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