我最近遇到了一个问题,即在升级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代码,因此它使用标准的C99语义为Inline关键字。这些语义与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中,内联表示函数的定义仅用于内线,并且程序中的其他地方还有另一个定义(无内联)。这意味着此程序是不完整的,因为如果添加未插入(例如,在没有优化的情况下编译时),则MAIN将对其他定义有尚未解决的引用。因此,我们将获得这样的(正确的)链接时间错误:
Undefined symbols:
"_add", referenced from:
_main in cc-y1jXIr.o
相比之下,GNU C89模式(默认情况下,在旧版本的GCC中使用)是C89标准和许多扩展。C89没有内联关键词,但GCC将其视为扩展名,只是将其视为优化器的提示。
有几种解决此问题的方法:
- 更改添加到静态内联函数。如果只有一个翻译单元需要使用该函数,这通常是正确的解决方案。静态内联函数始终在翻译单元中解决,因此您不必添加程序中其他位置的功能的非内部定义。
- 从此添加的定义中删除内联关键字。插入函数并不需要隐藏的关键字,也不保证它将是。一些编译器完全忽略了它。Clang将其视为程序员的温和建议。
- 提供了程序中其他地方的外部(非内部)定义。这两个定义必须等效!
- 通过将-std = gnu89添加到clang选项的集合中,在GNU C89方言中编译。仅当无法更改程序源或程序还依赖其他无法更改的C89特定行为时,才建议使用此选项。
所有这些仅适用于C代码;c 中的内联含义与gnu89或c99中的含义非常不同。