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

gcc test.c -o test -lm

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


当前回答

如果我放入stdlib.h或stdio.h,我不需要链接它们,但我必须在编译时链接:

Stdlib.h, stdio.h是头文件。你把它们包括进来是为了方便。如果你链接到适当的库中,它们只预测哪些符号是可用的。实现在库文件中,这是函数真正存在的地方。

包含math.h只是获得对所有math函数的访问权的第一步。

此外,如果你不使用它的函数,你也不必链接到libm,即使你做了#include <math.h>,这只是一个关于符号的信息步骤,对于编译器来说。

Stdlib.h, stdio.h指的是libc中可用的函数,这些函数总是被链接在一起,这样用户就不必自己做了。

其他回答

这是个bug。你不必再显式地指定-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。

如果我放入stdlib.h或stdio.h,我不需要链接它们,但我必须在编译时链接:

Stdlib.h, stdio.h是头文件。你把它们包括进来是为了方便。如果你链接到适当的库中,它们只预测哪些符号是可用的。实现在库文件中,这是函数真正存在的地方。

包含math.h只是获得对所有math函数的访问权的第一步。

此外,如果你不使用它的函数,你也不必链接到libm,即使你做了#include <math.h>,这只是一个关于符号的信息步骤,对于编译器来说。

Stdlib.h, stdio.h指的是libc中可用的函数,这些函数总是被链接在一起,这样用户就不必自己做了。

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

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

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

因为time()和其他一些函数是内置在C库(libc)中定义的,GCC总是链接到libc,除非你使用- ffrestanding compile选项。然而,数学函数存在于libm中,并不是由gcc隐式链接的。