C语言 为什么要链接math库

一、相关问题

正常的 C 程序,像是使用了 stdio 或是 stdlib 等库的程序在编译时都是直接编译的,不需要指定任何链接选项。

例如:

gcc test.c -o test

但是如果程序中使用了 math 库,直接编译会报如下错误:

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

想要正确编译,就必须在其后加上 -lm 选项

例如:

gcc test.c -o test -lm

可是,为什么呢?为什么要手动链接呢?我在 StackOverflow 上找到了一些答案。

二、简答

stdli.hstdio.h 中的函数在 libc.so(或静态链接 libc.a)中有具体实现,它们是默认链接到你的可执行文件的(就像指定了 -lc 选项一样)。通过使用 -nostdlib-nodefaultlibs 选项可以避免 GCC 自动链接。

math.h 中的数学函数在 libm.so(或静态链接 libm.a)中有具体实现,但是 libm 并不是像 libc 一样默认链接的。关于 libm 和 libc 的不同,有一些荒谬的历史原因。

有趣的是,C++ 的 libstdc++ 需要 libm,所以如果使用 C++ 编译器(G++),就可以自动链接 libm。

三、荒谬的历史

因为 C 是个“古老”的语言,浮点运算器也是相对来说最近才出现并流行的。很久以前 C 语言在 8 位运算器上进行 32 位的 数值运算。这些实现很大一部分甚至没有可用的浮点数学库。

甚至是最早的 68000 机器,其浮点运算器也是相当昂贵的附加产品

在浮点运算器未出现前,如果要实现所有的浮点运算,需要一个十分庞大的库,并且计算效率很低。所以人们很少使用浮点数。人们尝试使用整数或缩放整数来模拟浮点运算,不到万不得已不会使用 math.h。通常为了避免这一情况发生,人们都有自己的近似值和查找表。

这种权衡存在了很久。有时有些数学库的名字叫做 “fastmath”。数学库的最优解决方案是什么?精确无误但效率低下的?还是不精确但效率高的?亦或是庞大的三角函数表?直到浮点运算器的出现和流行,这些问题才得以解决。浮点运算器一定会有误差,但科学及工程计算仍大量的依靠浮点运算器。只是在程序设计时就必需考虑精确度问题。

可以说,如果浮点运算器比 C 语言出现的早,或者浮点运算操作很简单的话,就不会出现这样尴尬的情况,肯定会有一个 “stdmath” 库。

参考:


若你喜欢我的文章,欢迎关注👇点赞👇评论👇收藏👇 谢谢支持!!!

posted @ 2022-04-07 11:36  王舰  阅读(655)  评论(0编辑  收藏  举报