如果我在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
这是什么原因呢?为什么我必须显式地链接数学库,而不是其他库?
当前回答
在《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.
其他回答
在《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.
注意,即使使用一些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?
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。
我猜,这是一种使根本不使用它的应用程序性能稍好一些的方法。以下是我的看法。
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。