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

gcc test.c -o test -lm

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


当前回答

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

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

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

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

不过这只是猜测。

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

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

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

其他回答

如前所述,C库libc默认是链接的,该库包含stdlib.h、stdio.h和其他几个标准头文件的实现。只是补充一下,根据“GCC介绍”,C语言中基本“Hello World”程序的链接器命令如下所示:

ld -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

注意第三行中链接C库的选项-lc。

stdio是标准C库的一部分,默认情况下,GCC将链接到该库。

数学函数实现在一个单独的libm文件中,默认情况下没有链接到该文件,因此必须指定它为-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 ?

来看看用法:

使用图书馆

这里给出一个解释:

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

(编辑)

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

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