如果我在C程序中包含<stdlib.h>或<stdio.h>,我在编译时不需要链接这些,但我必须链接到<math.h>,使用-lm与GCC,例如:

gcc test.c -o test -lm

这是什么原因呢?为什么我必须显式地链接数学库,而不是其他库?


当前回答

stdlib.h和stdio.h中的函数在libc中有实现。所以(或libc。A用于静态链接),默认情况下链接到可执行文件中(就像指定了-lc一样)。可以指示GCC使用- nodlib或-nodefaultlibs选项避免这种自动链接。

math.h中的数学函数在libm中有实现。所以(或libm。A表示静态链接),默认情况下不链接libm。libm/libc的分裂是有历史原因的,但没有一个令人信服。

有趣的是,c++运行时libstdc++需要libm,因此如果使用GCC (g++)编译c++程序,将自动链接到libm。

其他回答

因为荒谬的历史实践,没有人愿意修正。将C和POSIX所需的所有函数合并到一个库文件中,不仅可以避免反复询问这个问题,还可以在动态链接时节省大量的时间和内存,因为所链接的每个.so文件都需要文件系统操作来定位和查找它,并占用一些页面用于静态变量和重定位等。

所有函数都在一个库中,-lm, -lpthread, -lrt等选项都是无操作(或链接到空的.a文件)的实现是完全符合POSIX的,当然更可取。

注意:我谈论POSIX是因为C本身没有指定任何关于如何调用编译器的内容。因此,您可以将gcc -std=c99 -lm视为必须调用编译器以实现一致行为的特定实现方式。

在《GCC介绍-与外部库链接》中有关于链接到外部库的详细讨论。如果一个库是标准库(如stdio)的成员,则不需要指定编译器(实际上是链接器)来链接它们。

在阅读了一些其他的回答和评论后,我认为libc。参考文献和它链接到的libm参考文献都有很多关于为什么两者是分开的。

Note that many of the functions in 'libm.a' (the math library) are defined in 'math.h' but are not present in libc.a. Some are, which may get confusing, but the rule of thumb is this--the C library contains those functions that ANSI dictates must exist, so that you don't need the -lm if you only use ANSI functions. In contrast, `libm.a' contains more functions and supports additional functionality such as the matherr call-back and compliance to several alternative standards of behavior in case of FP errors. See section libm, for more details.

我认为这有点武断。您必须在某个地方划清界限(哪些库是默认的,哪些库需要指定)。

它让你有机会用一个具有相同功能的不同产品来替代它,但我不认为这样做很常见。

我认为GCC这样做是为了保持与原始cc可执行文件的向后兼容性。我猜cc为什么这样做是因为构建时间——cc是为比我们现在的功率小得多的机器编写的。许多程序没有任何浮点数学运算,它们可能会将所有不常用的库从默认值中删除。我猜Unix操作系统的构建时间和与之配套的工具是驱动因素。

我猜,这是一种使根本不使用它的应用程序性能稍好一些的方法。以下是我的看法。

x86操作系统(我想还有其他操作系统)需要在上下文切换中存储FPU状态。然而,大多数操作系统只在应用程序第一次尝试使用FPU时才会保存/恢复这种状态。

除此之外,在数学库中可能还有一些基本代码,可以在加载库时将FPU设置为正常的基状态。

所以,如果你根本不链接任何数学代码,这一切都不会发生,因此操作系统根本不需要保存/恢复任何FPU状态,使上下文切换稍微更有效。

不过这只是猜测。

同样的基本前提仍然适用于非fpu情况(前提是,它是为了让没有使用libm的应用程序表现得更好)。

例如,如果有一个在c语言早期很可能出现的软fpu,那么将libm分开可以防止大量不必要的大代码(如果使用它的话会很慢)被链接。

此外,如果只有静态链接可用,则适用类似的论点,即它将保持可执行文件的大小和编译时间较短。

这里给出一个解释:

因此,如果您的程序使用数学函数并包含math.h,那么您需要通过传递-lm标志显式地链接数学库。这种特殊分离的原因是数学家对计算数学的方式非常挑剔,他们可能希望使用自己的数学函数实现而不是标准实现。如果数学函数集中到libc中。A这是不可能的。

(编辑)

不过,我不确定我是否同意这一点。如果你有一个库,它提供了,比如说,sqrt(),并且你在标准库之前传递它,Unix链接器会获取你的版本,对吗?