GCC 内置函数 - 2003 年与 2019 年行为



Brian Gough的">GCC简介"一书的第14页,作者希望显示由于没有向gcc提供libm库而导致的链接器错误,该库sqrt函数的代码

所在的位置:
$ gcc -Wall calc.c -o calc
/tmp/ccbR6Ojm.o: In function ‘main’:
/tmp/ccbR6Ojm.o(.text+0x19): undefined reference to ‘sqrt’

文件calc.c(调用函数sqrt的位置)如下:

#include <math.h>
#include <stdio.h>
int main (void)
{
double x = sqrt (2.0);
printf ("The square root of 2.0 is %fn", x);
return 0;
}

本书是2003年出版的。 在我当前的 Ubuntu Linux 18 上,我无法重现链接错误:它链接并工作,打印正确的结果:

$ ./calc
1.414214

ldd calc发现libm.so共享库在运行时没有被调用。当然,这里也不涉及静态库libm.a。 那么 gcc 如何处理函数sqrt呢?我发现在这种情况下它使用sqrtGCC 内置函数。 其代码在编译时插入到calc.o对象文件中。所以没有"未定义的引用"错误。

第一个问题:这就是整个故事还是我错过了什么?

第二个问题:为什么在2003年(本书撰写时)到现在,关于GCC内置函数的行为发生了如此大的变化?(在我看来,实际上使整个示例无效)

第三个问题:为什么作者用他的例子(例如$ gcc -Wall calc.c -lm -o cal)暗示将使用静态库libc.a,而实际上在Linux中,语法调用动态库libm.so?这是特定于Linux而不是GNU GCC的吗?我误会什么?

我认为这是由于常量值的优化。现代GCC可以计算sqrt (2.0)的精确值。如果您强制它不使用内置的内置函数-fno-builtin,它仍然无法链接。此外,如果您稍微更改代码以使sqrt()参数不是文字,它将无法链接:

#include <math.h>
#include <stdio.h>
double t = 2.0;
int main (void)
{
double x = sqrt (t);
printf ("The square root of 2.0 is %fn", x);
return 0;
}

这会产生链接错误:

> gcc -o test test.c              
/usr/bin/ld: /tmp/ccLjHnQx.o: in function `main':
test.c:(.text+0x11): undefined reference to `sqrt'
collect2: error: ld returned 1 exit status

关于您的第三个问题,-lm并不意味着静态库,AFAIK。

最新更新