为什么在 C 程序中内联函数时会出现 clang 链接错误?

Why do I get a linking error with clang when inlining a function in a C program?

为什么下面的程序不能用 clang 编译?

#include <stdio.h>

inline int f() {
  return 42;
}

int main() {
  printf("%d\n", f());
}

我得到以下信息:

$ clang -o inline inline.c
Undefined symbols for architecture arm64:
  "_f", referenced from:
      _main in inline-975155.o
ld: symbol(s) not found for architecture arm64
clang-12: error: linker command failed with exit code 1 (use -v to see invocation)

但是我可以用clang++编译它就好了。 C 与 C++ 中的 inline 之间是否存在细微差别?

在 C99 中,当编译器无法内联时,您需要提供函数的备用(非内联)定义。参见 https://clang.llvm.org/compatibility.html#inline

其中一个解决方案可能对您有用,就是将定义设为静态:

#include <stdio.h>

static inline int f() {
  return 42;
}

int main() {
  printf("%d\n", f());
}

将按您的预期工作。

以下是链接的 clang 页面中列出的所有选项:

  • Change add to a static inline function. This is usually the right solution if only one translation unit needs to use the function. static inline functions are always resolved within the translation unit, so you won't have to add a non-inline definition of the function elsewhere in your program.
  • Remove the inline keyword from this definition of f. The inline keyword is not required for a function to be inlined, nor does it guarantee that it will be. Some compilers ignore it completely. Clang treats it as a mild suggestion from the programmer.
  • Provide an external (non-inline) definition of f somewhere else in your program. The two definitions must be equivalent!
  • Compile in the GNU C89 dialect by adding -std=gnu89 to the set of Clang options. This option is only recommended if the program source cannot be changed or if the program also relies on additional C89-specific behavior that cannot be changed.

很简单:如果不启用优化,内联将不起作用。

https://godbolt.org/z/KrWq4PGhd

要解决这个问题,您需要指示编译器也发出非内联版本:

extern inline int f() {
  return 42;
}

然后它在两种情况下都有效(内联或不内联)

https://godbolt.org/z/dh3G18PqK

CLANG 的工作方式完全相同:

https://godbolt.org/z/ssMnzf5MG

https://godbolt.org/z/ssMnzf5MG

C 2018标准6.7.4 7中说内联定义不提供外部定义:

… An inline definition does not provide an external definition for the function…

并且编译器可以使用内联定义或外部定义:

… It is unspecified whether a call to the function uses the inline definition or the external definition.

因此,编译器可以将对 f 的调用编译为对内联定义的调用,这不会导致 link 错误,或者编译为对外部定义的调用,这如果您没有提供外部定义,将导致 link 错误。编译器的选择可能会受到优化开关和其他设置的影响。

C++ 标准没有这个措辞(但我会留给其他人提供对 C++ 标准的额外解释)。