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

gcc test.c -o test -lm

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


当前回答

所有像stdio.h和stdlib.h这样的库都在libc中实现。或者libc。默认情况下被链接器链接。libc的库。因此在编译时自动链接并包含在可执行文件中。

但是math.h在libm中有它的实现。或者是libm。A是独立于lib。所以。默认情况下它不会被链接,您必须在GCC中编译程序时使用-lm标志手动链接它。

GNU GCC团队将其设计为与其他头文件分离,而默认情况下其他头文件会被链接,但math.h文件不会。

这里阅读第14.3项,如果你愿意,你可以全部阅读: math.h需要连接的原因

看看这篇文章:为什么我们必须在GCC中链接math.h ?

来看看用法:

使用图书馆

其他回答

在《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.

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

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

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

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

不过这只是猜测。

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

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

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

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

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

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

这是个bug。你不必再显式地指定-lm了。也许如果有足够多的人抱怨,它就会被修复。(我并不真的相信这一点,因为坚持这种区别的维护者显然非常固执,但我希望如此。)

这里给出一个解释:

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

(编辑)

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