如果我在C程序中包含<stdlib.h>或<stdio.h>,我在编译时不需要链接这些,但我必须链接到<math.h>,使用-lm与GCC,例如:
gcc test.c -o test -lm
这是什么原因呢?为什么我必须显式地链接数学库,而不是其他库?
如果我在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中可用的函数,这些函数总是被链接在一起,这样用户就不必自己做了。
其他回答
stdio是标准C库的一部分,默认情况下,GCC将链接到该库。
数学函数实现在一个单独的libm文件中,默认情况下没有链接到该文件,因此必须指定它为-lm。顺便说一下,这些头文件和库文件之间没有关系。
我认为这有点武断。您必须在某个地方划清界限(哪些库是默认的,哪些库需要指定)。
它让你有机会用一个具有相同功能的不同产品来替代它,但我不认为这样做很常见。
我认为GCC这样做是为了保持与原始cc可执行文件的向后兼容性。我猜cc为什么这样做是因为构建时间——cc是为比我们现在的功率小得多的机器编写的。许多程序没有任何浮点数学运算,它们可能会将所有不常用的库从默认值中删除。我猜Unix操作系统的构建时间和与之配套的工具是驱动因素。
请记住,C是一种古老的语言,而fpu是相对较新的现象。我第一次看到C语言是在8位处理器上,即使是32位整数运算也要做很多工作。许多实现甚至没有可用的浮点数学库!
即使在最初的68000台机器上(Mac、Atari ST、Amiga),浮点协处理器也常常是昂贵的附加组件。
要完成所有这些浮点运算,您需要一个相当大的库。数学运算会很慢。所以你很少使用浮动。你试着用整数或按比例的整数来做所有的事情。当你必须包括math.h时,你咬紧牙关。通常,您会编写自己的近似和查找表来避免这种情况。
Trade-offs existed for a long time. Sometimes there were competing math packages called "fastmath" or such. What's the best solution for math? Really accurate but slow stuff? Inaccurate but fast? Big tables for trig functions? It wasn't until coprocessors were guaranteed to be in the computer that most implementations became obvious. I imagine that there's some programmer out there somewhere right now, working on an embedded chip, trying to decide whether to bring in the math library to handle some math problem.
这就是数学不是标准的原因。许多或大多数程序都没有使用一个浮点数。如果fpu一直存在,浮点数和双精度浮点数的操作成本一直很低,毫无疑问,就会有一个“标准数学”。
如前所述,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。
我猜,这是一种使根本不使用它的应用程序性能稍好一些的方法。以下是我的看法。
x86操作系统(我想还有其他操作系统)需要在上下文切换中存储FPU状态。然而,大多数操作系统只在应用程序第一次尝试使用FPU时才会保存/恢复这种状态。
除此之外,在数学库中可能还有一些基本代码,可以在加载库时将FPU设置为正常的基状态。
所以,如果你根本不链接任何数学代码,这一切都不会发生,因此操作系统根本不需要保存/恢复任何FPU状态,使上下文切换稍微更有效。
不过这只是猜测。
同样的基本前提仍然适用于非fpu情况(前提是,它是为了让没有使用libm的应用程序表现得更好)。
例如,如果有一个在c语言早期很可能出现的软fpu,那么将libm分开可以防止大量不必要的大代码(如果使用它的话会很慢)被链接。
此外,如果只有静态链接可用,则适用类似的论点,即它将保持可执行文件的大小和编译时间较短。