如果我在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
这是什么原因呢?为什么我必须显式地链接数学库,而不是其他库?
当前回答
注意,即使使用一些C数学函数,-lm也不一定总是需要指定。
例如,下面这个简单的程序:
#include <stdio.h>
#include <math.h>
int main() {
printf("output: %f\n", sqrt(2.0));
return 0;
}
可以编译并成功运行如下命令:
gcc test.c -o test
它在GCC 7.5.0 (Ubuntu 16.04)和GCC 4.8.0 (CentOS 7)上进行了测试。
这篇文章给出了一些解释:
你调用的数学函数是由编译器内置函数实现的
参见:
GCC提供的其他内置函数 如何让gcc编译器不优化标准库函数调用如printf?
其他回答
请记住,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一直存在,浮点数和双精度浮点数的操作成本一直很低,毫无疑问,就会有一个“标准数学”。
我猜,这是一种使根本不使用它的应用程序性能稍好一些的方法。以下是我的看法。
x86操作系统(我想还有其他操作系统)需要在上下文切换中存储FPU状态。然而,大多数操作系统只在应用程序第一次尝试使用FPU时才会保存/恢复这种状态。
除此之外,在数学库中可能还有一些基本代码,可以在加载库时将FPU设置为正常的基状态。
所以,如果你根本不链接任何数学代码,这一切都不会发生,因此操作系统根本不需要保存/恢复任何FPU状态,使上下文切换稍微更有效。
不过这只是猜测。
同样的基本前提仍然适用于非fpu情况(前提是,它是为了让没有使用libm的应用程序表现得更好)。
例如,如果有一个在c语言早期很可能出现的软fpu,那么将libm分开可以防止大量不必要的大代码(如果使用它的话会很慢)被链接。
此外,如果只有静态链接可用,则适用类似的论点,即它将保持可执行文件的大小和编译时间较短。
在《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.
如果我放入stdlib.h或stdio.h,我不需要链接它们,但我必须在编译时链接:
Stdlib.h, stdio.h是头文件。你把它们包括进来是为了方便。如果你链接到适当的库中,它们只预测哪些符号是可用的。实现在库文件中,这是函数真正存在的地方。
包含math.h只是获得对所有math函数的访问权的第一步。
此外,如果你不使用它的函数,你也不必链接到libm,即使你做了#include <math.h>,这只是一个关于符号的信息步骤,对于编译器来说。
Stdlib.h, stdio.h指的是libc中可用的函数,这些函数总是被链接在一起,这样用户就不必自己做了。
注意,即使使用一些C数学函数,-lm也不一定总是需要指定。
例如,下面这个简单的程序:
#include <stdio.h>
#include <math.h>
int main() {
printf("output: %f\n", sqrt(2.0));
return 0;
}
可以编译并成功运行如下命令:
gcc test.c -o test
它在GCC 7.5.0 (Ubuntu 16.04)和GCC 4.8.0 (CentOS 7)上进行了测试。
这篇文章给出了一些解释:
你调用的数学函数是由编译器内置函数实现的
参见:
GCC提供的其他内置函数 如何让gcc编译器不优化标准库函数调用如printf?