gcc - 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 %f\n", x);
return 0;
}
这本书是 2003 年的。在我当前的 Ubuntu Linux 18 上,我无法重现链接错误:它链接并工作,打印正确的结果:
$ ./calc
1.414214
我发现ldd calc
共享libm.so
库在运行时没有被调用。当然这里也不libm.a
涉及静态库。那么 gcc 是如何处理函数的sqrt
呢?我发现在这种情况下它使用了sqrt
GCC 内置函数。它的代码在编译时被插入到calc.o
目标文件中。所以没有“未定义的引用”错误。
第一个问题:这是整个故事还是我错过了什么?
第二个问题:为什么 GCC 内置函数的这种行为在 2003 年(本书撰写时)和现在之间发生了如此大的变化?(在我看来,实际上使整个示例无效)
第三个问题:为什么作者的示例(例如$ gcc -Wall calc.c -lm -o cal
)暗示libc.a
将使用静态库,而实际上在 Linux 中该语法调用动态库libm.so
?这是否特定于 Linux 而不是 GNU GCC?我错过了什么?
解决方案
我认为这是由于对常数值的优化。现代 GCC 可以计算sqrt (2.0)
. 如果你强制它不使用内置插件-fno-builtin
,它仍然无法链接。此外,如果您稍微更改代码以使 to 的参数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 %f\n", 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。
推荐阅读
- javascript - 如何在两个反应兄弟组件之间传递数据?
- java - 如何在restful控制器的返回对象中设置成员变量
- linux - 如何将主机目录挂载到正在运行的 docker 容器中
- mean-stack - 数据更改后Angular UI不更新
- java - 如何在 Eclipse 中删除 maven 依赖 jar
- php - 有没有办法只使用 PHP 和 JavaScript 来提交表单而不刷新页面?
- reactjs - 如何使用 react-redux-firebase 从 firestore 获取子集合
- javascript - DatePicker 在 React 自定义 Hook 中不起作用
- node.js - 如何从 mp4 视频 url(存储在 amazon S3 中)创建 m3u8 播放列表并将视频块(.ts 文件)和 .m3u8 文件存储回另一个 S3?
- python - 问题在 PyCharm 中运行 Python 3.7 以执行 Twitter Bot(通过 Tweepy)