代码之家  ›  专栏  ›  技术社区  ›  Nope

为什么你必须用C链接数学库?

  •  329
  • Nope  · 技术社区  · 17 年前

    如果我包括 <stdlib.h> <stdio.h> <math.h> -lm

    gcc test.c -o test -lm
    

    14 回复  |  直到 3 年前
        1
  •  305
  •   Peter Mortensen Pieter Jan Bonestroo    3 年前

    功能在 stdlib.h stdio.h 在中有实现 libc.so (或 libc.a 用于静态链接),默认情况下链接到可执行文件中(就像 -lc 已指定)。可以指示GCC避免与 -nostdlib -nodefaultlibs

    math.h 在中有实现 libm.so (或 libm.a libm libm / libc

    有趣的是,C++运行时 libstdc++ libm ,所以如果你用GCC编译一个C++程序( g++ libm 链接进去。

        2
  •  98
  •   Nosredna    17 年前

    浮点数学库可用!

    即使在最初的68000台机器(Mac、Atari ST、Amiga)上,浮点协处理器也往往是昂贵的附加组件。

    要进行所有浮点运算,你需要一个相当大的库。数学会很慢。所以你很少使用浮子。你试图用整数或缩放整数做任何事情。当你不得不包括数学时,你咬牙切齿。通常,你会写自己的近似值和查找表来避免这种情况。

    这就是为什么数学不是 标准 。许多或大多数程序没有使用单个浮点数。如果FPU一直存在,浮点数和双精度总是很便宜,毫无疑问,会有一个“标准数学”。

        3
  •  88
  •   Aaron Hall    9 年前

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

    一种所有函数都在一个库中的实现 -lm , -lpthread , -lrt ,等等。选项均为无操作(或链接为空 .a

    gcc -std=c99 -lm

        4
  •  33
  •   Peter Mortensen Pieter Jan Bonestroo    3 年前

    因为 time() builtin 在C库中定义( libc )自身和GCC 总是 链接到libc 你使用 -ffreestanding 编译选项。然而,数学函数存在于 libm gcc没有隐式链接。

        5
  •  29
  •   Bastien Léonard    17 年前

    给出了一个解释 here :

    因此,如果你的程序使用数学函数,包括 math.h ,然后您需要通过传递 -lm 旗帜。这种特殊分离的原因是数学家对计算数学的方式非常挑剔,他们可能想使用自己的数学函数实现,而不是标准实现。如果将数学函数集中到 libc.a 那是不可能的。

    [编辑]

    不过,我不确定我是否同意这一点。如果你有一个图书馆,比如说, sqrt() ,然后在标准库之前传递它,Unix链接器将获取您的版本,对吗?

        6
  •  8
  •   Peter Mortensen Pieter Jan Bonestroo    3 年前

    关于与外部图书馆的链接,有一个深入的讨论 An Introduction to GCC - Linking with external libraries 。如果一个库是标准库(如stdio)的成员,那么您不需要向编译器(实际上是链接器)指定链接它们。

    libc.a reference

    请注意,'libm.a'(数学库)中的许多函数在'math.h'中定义,但在libc.a中不存在。有些函数存在,这可能会让人感到困惑,但经验法则是这样的——C库包含ANSI规定必须存在的函数,所以如果你只使用ANSI函数,就不需要-lm。相比之下,“libm.a”包含更多函数,并支持其他功能,如matherr回调和在FP错误时遵守几种替代行为标准。有关更多详细信息,请参阅libm部分。

        7
  •  6
  •   Peter Mortensen Pieter Jan Bonestroo    3 年前

    正如ephemient所说,默认情况下,C库libc是链接的,该库包含stdlib.h、stdio.h和其他几个标准头文件的实现。只是为了补充一下,根据“ An Introduction to 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
    

    注意选项 -lc 在连接C库的第三行中。

        8
  •  4
  •   Adrian Panasiuk    17 年前

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

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

    包括 math.h

    libm #include <math.h> 这只是编译器关于符号的一个信息步骤。

    stdlib。h , stdio。h libc ,它总是被链接进来,这样用户就不必自己做了。

        9
  •  4
  •   Steve Summit    5 年前

    -lm 再。也许如果有足够多的人抱怨它,它就会得到解决。(我并不真的相信这一点,因为维持这种区别的维护者显然是 非常 固执,但我可以希望。)

        10
  •  4
  •   Peter Mortensen Pieter Jan Bonestroo    3 年前

    我认为这有点武断。你必须在某个地方画一条线(哪些库是默认的,哪些需要指定)。

    它让你有机会用具有相同功能的另一个替换它,但我认为这样做并不常见。

    我认为GCC这样做是为了保持与原始版本的向后兼容性 cc 可执行。我猜为什么 CC 这是因为构建时间吗-- CC

        11
  •  3
  •   Peter Mortensen Pieter Jan Bonestroo    3 年前

    猜测 这是一种让根本不使用它的应用程序性能稍微好一点的方法。以下是我对此的看法。

    例如,如果有一个软FPU,这可能是在C的早期 libm 分离可以防止不必要地链接大量大型(如果使用的话速度很慢)代码。

    此外,如果只有静态链接可用,那么一个类似的论点也适用,即它将保持可执行文件的大小并缩短编译时间。

        12
  •  2
  •   Peter Mortensen Pieter Jan Bonestroo    3 年前

    stdio.h stdlib.h libc.so libc.a libc.so

    但是 math.h 其实现方式为 libm.so libm.a 它与 libc.so 。默认情况下,它不会链接,您必须在GCC中编译程序时使用 -lm

    GNU GCC团队将其设计为与其他头文件分开,默认情况下其他头文件会链接,但math.h文件不会。

    在这里阅读项目编号14.3,如果你愿意,你可以全部阅读: Reason why math.h is needs to be linked

    看看这篇文章: Why do we have to link math.h in GCC?

    Using the library

        13
  •  2
  •   Peter Mortensen Pieter Jan Bonestroo    3 年前

    请注意 -lm

    例如,以下简单程序:

    #include <stdio.h>
    #include <math.h>
    
    int main() {
    
        printf("output: %f\n", sqrt(2.0));
        return 0;
    }
    

    可以使用以下命令成功编译和运行:

    gcc test.c -o test
    

    Ubuntu 16.04 CentOS 7.

    here

    您调用的数学函数由编译器内置函数实现

    另请参见:

        14
  •  2
  •   Peter Mortensen Pieter Jan Bonestroo    3 年前

    是标准C库的一部分,默认情况下,GCC将链接到该库。

    libm 默认情况下未链接到的文件,因此您必须指定它 -lm 顺便说一句,这些头文件和库文件之间没有关系。

    推荐文章