Nop*_*ope 241 c compilation math.h
如果我包含<stdlib.h>或<stdio.h>在C程序中,我不必在编译时链接这些,但我必须链接到<math.h>,使用-lmgcc,例如:
gcc test.c -o test -lm
Run Code Online (Sandbox Code Playgroud)
这是什么原因?为什么我必须显式链接数学库而不是其他库?
eph*_*ent 232
在功能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(g++)编译C++程序,您将自动libm链接到.
Nos*_*dna 74
请记住,C是一种古老的语言,FPU是一种相对较新的现象.我首先在8位处理器上看到了C,即使是32位整数运算也需要做很多工作.其中许多实现甚至没有可用的浮点数学库!
即使在最初的68000台机器(Mac,Atari ST,Amiga)上,浮点协处理器通常也是昂贵的附加装置.
要做所有的浮点数学,你需要一个相当大的库.数学运算会很慢.所以你很少使用花车.您尝试使用整数或缩放整数执行所有操作.当你必须包括math.h时,你咬紧牙关.通常,您会编写自己的近似值和查找表以避免它.
权衡取舍存在很长时间.有时会有竞争性的数学包称为"fastmath"等.什么是数学的最佳解决方案?真的准确但缓慢的东西?不准确但速度快?trig功能的大表?直到协处理器被保证在计算机中,大多数实现变得明显.我想现在有一些程序员在那里,在嵌入式芯片上工作,试图决定是否引入数学库来处理一些数学问题.
这就是数学不标准的原因.许多或大多数程序都没有使用单个浮点数.如果FPU一直存在并且浮动和双打总是便宜的操作,毫无疑问会有一个"stdmath".
R..*_*R.. 72
由于荒谬的历史实践,没有人愿意修复.将C和POSIX所需的所有功能整合到单个库文件中不仅可以避免一遍又一遍地询问这个问题,而且还可以在动态链接时节省大量时间和内存,因为.so链接的每个文件都需要文件系统操作定位和找到它,以及几个页面的静态变量,重定位等.
所有功能都在一个库的实现和-lm,-lpthread,-lrt,等选项都是无操作(或链接到空.a文件)是完全符合的POSIX,当然最好.
注意:我在谈论POSIX,因为C本身没有指定有关如何调用编译器的任何内容.因此,您可以将其gcc -std=c99 -lm视为特定于实现的方式,必须为符合行为调用编译器.
ism*_*ail 33
因为C库()本身定义了time()一些其他函数,并且GCC 总是链接到libc,除非你使用compile选项.但是,数学函数存在于gcc中并未隐式链接.builtinlibc-ffreestandinglibm
Bas*_*ard 26
这里给出一个解释:
因此,如果您的程序使用数学函数和包含
math.h,那么您需要通过传递-lm标志显式链接数学库.这种特殊分离的原因是数学家对计算数学的方式非常挑剔,他们可能想要使用他们自己的数学函数实现而不是标准实现.如果将数学函数集中到libc.a其中就不可能这样做.
[编辑]
不过,我不确定我是否同意这一点.如果你有一个库提供,比如说,sqrt()并且你在标准库之前传递它,那么Unix链接器将会使用你的版本,对吗?
An Introduction to GCC - Linking with external libraries 中对链接到外部库进行了深入讨论。如果库是标准库的成员(如 stdio),那么您不需要指定编译器(实际上是链接器)来链接它们。
编辑:在阅读了其他一些答案和评论后,我认为libc.a 参考和它链接到的 libm 参考有很多关于为什么两者分开的说法。
请注意,“libm.a”(数学库)中的许多函数在“math.h”中定义,但在 libc.a 中不存在。有些是,这可能会令人困惑,但经验法则是这样的——C 库包含 ANSI 规定必须存在的那些函数,因此如果您只使用 ANSI 函数,则不需要 -lm。相比之下,`libm.a' 包含更多功能并支持附加功能,例如 matherr 回调和在 FP 错误的情况下遵守几种替代行为标准。有关更多详细信息,请参阅 libm 部分。
正如ephemient所说,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
Run Code Online (Sandbox Code Playgroud)
注意链接C库的第三行中的选项-lc.