<stdlib.h>
或<stdio.h>
,则编译时不需要链接这些库,但是必须使用-lm链接<math.h>
,例如使用GCC编译。gcc test.c -o test -lm
这是为什么?为什么我必须明确链接数学库,但不需要链接其他库?
<stdlib.h>
或<stdio.h>
,则编译时不需要链接这些库,但是必须使用-lm链接<math.h>
,例如使用GCC编译。gcc test.c -o test -lm
这是为什么?为什么我必须明确链接数学库,但不需要链接其他库?
stdlib.h
和stdio.h
中的函数实现在libc.so
(或者对于静态链接是libc.a
)中,这个库默认会被链接到你的可执行文件中(就像指定了-lc
一样)。使用-nostdlib 或 -nodefaultlibs 选项可以告诉GCC避免这种自动链接。
math.h
中的数学函数实现在libm.so
(或者对于静态链接是libm.a
)中,但libm
并不会默认链接进来。历史原因导致了这种libm
/libc
分离方式,但这些原因都不是很令人信服。libstdc++
需要libm
,因此如果你使用GCC(g++
)编译一个C++程序,libm
会被自动链接进来。请记住C语言是一种古老的语言,FPU则是一个相对较新的现象。我第一次在8位处理器上看到C语言时,即使进行32位整数运算也需要大量工作。许多这样的实现甚至没有可用的浮点数学库!
即使在第一批68000计算机(Mac、Atari ST和Amiga)上,浮点数协处理器通常也是昂贵的附加组件。
要进行所有这些浮点数学运算,您需要一个非常大的库。而且计算速度会很慢,因此您很少使用浮点数。您尝试使用整数或缩放整数来完成所有任务。当您不得不包含math.h时,要咬紧牙关。通常情况下,您会编写自己的近似值和查找表来避免使用它。
长期以来存在着权衡取舍。有时会有竞争的数学软件包,称为“fastmath”或类似名称。什么是数学问题的最佳解决方案?真正精确但缓慢的东西?不准确但快速的东西?三角函数的大型表格?直到协处理器可以保证在计算机中存在,大多数实现才变得明显。我想象中,现在某个地方有一位程序员正在嵌入式芯片上工作,试图决定是否引入数学库来处理某些数学问题。
这就是为什么数学不是标准的原因。许多甚至大多数程序都没有使用单个浮点数。如果FPUs一直存在,并且浮点数和双精度浮点数始终便宜易操作,毫无疑问会出现“stdmath”。
libm
,但是自 C89 起,数学库一直是标准库的一部分,甚至在此之前,K&R 也 事实上 将其标准化了,因此你提到的 "stdmath" 说法不合适。 - Fred Foo由于无法解决的荒谬历史惯例,C和POSIX所需的所有功能都合并到单个库文件中不仅可以避免反复问这个问题,而且在动态链接时会节省大量时间和内存,因为每个链接的.so
文件都需要进行文件系统操作来查找它,并且需要一些页面来处理其静态变量、重定位等。
如果所有函数都在一个库中,并且-lm
、-lpthread
、-lrt
等选项都是空操作(或链接到空的.a
文件),那么实现就是完全符合 POSIX 标准的,而且肯定更可取。
注意:我谈论的是 POSIX,因为 C 本身并没有指定如何调用编译器。因此,您可以将gcc -std=c99 -lm
视为实现特定的编译器调用方式,以获得符合标准的行为。
strace
中的一个计时选项来观察启动时间花费在动态链接上的数量,或者比较在所有标准工具都是静态链接的系统上运行 ./configure
和在动态链接的系统上运行的区别。即使是主流的桌面应用程序开发人员和系统集成商也意识到动态链接的成本;这就是为什么会有类似于 prelink 的东西存在。我相信你可以在一些论文中找到基准测试数据。 - R.. GitHub STOP HELPING ICEstrace -tt
命令可以轻松地显示动态链接所花费的时间,不太美观。在 Linux 上,检查 /proc/sys/smaps
可以显示额外库的内存开销。 - R.. GitHub STOP HELPING ICE由于time()
和其他一些函数是C库(libc
)中定义的内置函数,GCC编译器总是链接到libc,除非您使用-ffreestanding编译选项。但是数学函数位于libm
中,GCC不会自动链接。
在这里给出了一个解释 (链接):
如果你的程序使用数学函数并包含
math.h
,那么你需要通过传递-lm
标志显式链接数学库。这种特定分离的原因是数学家非常挑剔关于他们的数学是如何被计算的,并且他们可能想使用自己实现的数学函数而不是标准实现。如果将数学函数合并到libc.a
中,那么这是不可能的。
[编辑]
我不确定我同意这个解释。如果你有一个提供了sqrt()
的库,并且在标准库之前传递它,Unix链接器会采用你的版本,对吗?
sqrt
的自定义函数(非静态)会导致程序出现未定义行为。 - R.. GitHub STOP HELPING ICE-lm
是完全可选的。有什么想法吗? - Donghua Liu在GCC介绍-链接到外部库中,有关于链接到外部库的全面讨论。如果一个库是标准库的成员(如stdio),那么您不需要告诉编译器(实际上是链接器)链接它们。
阅读其他答案和评论后,我认为libc.a参考文献以及它链接的libm参考文献都对为什么这两个库是分开的有很多解释。
请注意,'libm.a'(数学库)中的许多函数在'math.h'中定义,但在libc.a中不存在。其中一些可能会令人困惑,但经验法则是这样的 - C库包含ANSI指定必须存在的函数,因此如果只使用ANSI函数,则不需要-lm。相反,`libm.a'包含更多功能并支持附加功能,例如matherr回调和在FP错误情况下符合几种替代行为的标准。有关详细信息,请参见libm部分。
sqrt
函数的程序时,不需要通过 -lm
包含库也能正常工作。谢谢! - L_Kld -dynamic-linker /lib/ld-linux.so.2 /usr/lib/crt1.o
/usr/lib/crti.o /usr/libgcc-lib /i686/3.3.1/crtbegin.o
-L/usr/lib/gcc-lib/i686/3.3.1 hello.o -lgcc -lgcc_eh -lc
-lgcc -lgcc_eh /usr/lib/gcc-lib/i686/3.3.1/crtend.o /usr/lib/crtn.o
这是一个错误。你不应该再显式地指定-lm
了。也许如果有足够多的人抱怨,它会被修复。 (我并不真正相信这一点,因为坚持这种区分的维护者显然非常固执,但我可以希望。)
GCC
的一个 bug? - chenzhongpu