【发布时间】:2011-07-22 02:52:54
【问题描述】:
当我编写一个使用 math.h 库中的函数的程序时,为什么我必须显式链接到 libm,即使它们是 C 标准库的一部分?
例如,当我想使用sin() 函数时,我需要#include <math.h>,但我还需要将-lm 传递给GCC。但是对于标准库中的任何其他库,我不必这样做。为什么会有差异?
【问题讨论】:
当我编写一个使用 math.h 库中的函数的程序时,为什么我必须显式链接到 libm,即使它们是 C 标准库的一部分?
例如,当我想使用sin() 函数时,我需要#include <math.h>,但我还需要将-lm 传递给GCC。但是对于标准库中的任何其他库,我不必这样做。为什么会有差异?
【问题讨论】:
在过去,链接器很慢,将大部分未使用的数学代码与其他代码分开可以加快编译过程。今天的差别不是很大,因此您可以将-lm 选项添加到您的默认编译器配置中。
请注意,标头 <math.h>(或任何其他标头)不包含代码。它包含有关代码的信息,特别是如何调用函数。代码本身在库中。我的意思是,您的程序不使用 "<math.h> 库",它使用数学库并使用在 <math.h> 标头中声明的原型。
【讨论】:
这与在大多数实现中必须显式链接到 libpthread 的原因相同。当标准库中添加了一些新的和可怕的东西时,它通常首先被实现为一个单独的附加库,它用符合新要求的版本覆盖旧标准库实现中的一些符号,同时还添加了很多新的接口。如果某些历史实现在libm 中有单独的printf 版本用于浮点打印,我不会感到惊讶,而主libc 中的“轻”版本缺少浮点。如果我没记错的话,ISO C 基本原理文档中实际上提到并鼓励了这种实现。
当然,从长远来看,像这样将标准库分开会导致更多的问题而不是好处。最糟糕的部分可能是动态链接程序的加载时间和内存使用量增加。
【讨论】:
实际上,对于大多数数学函数,您通常不需要链接到 libm 的原因是这些函数是由您的编译器内联的。如果不是这种情况,您的程序将无法在平台上链接。
【讨论】:
libm 的大部分内容是不可能内联的,除非您的内联函数限制为几 KB,或者您启用了像 -ffast-math 这样的 hack,它允许编译器生成不正确但快速的代码。
sin() 的程序将不需要在 x86 上链接到 libm,从而隐藏缺少的库引用。
sin指令可以直接实现sin()吗?如果我没记错的话,首先需要一个重要的参数缩减步骤。
fabs() 在 x86 上更好。我最初的观点仍然成立:如果您使用的所有函数都是内联的,那么即使数学库没有链接,程序也会链接并正常工作,但是由于显而易见的原因,这不是可移植的。