如果我包含<stdlib.h>或<stdio.h>在C程序中,我不必在编译时链接这些,但我必须链接到<math.h>,使用-lmgcc,例如:
gcc test.c -o test -lm
Run Code Online (Sandbox Code Playgroud)
这是什么原因?为什么我必须显式链接数学库而不是其他库?
我刚刚发现-lmgcc需要这个标志,以便编译一个从数学库中引用函数的程序.我想知道为什么在编译包含其他库(如时间库)的程序时不需要显式链接标志.如果我编写一个time()调用该函数的程序,即使没有链接选项也可以编译没有任何问题.但是如果没有-lm旗帜,那么涉及数学库的程序将无法运行.
任何人都可以解释这种行为背后的原因吗?谢谢你的时间.
对于以下C源代码:
#include <math.h>
int main(void)
{
double x;
x = log(0.0);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
当我编译时gcc -lm,我得到:
/tmp/ccxxANVH.o: In function `main':
a.c:(.text+0xd): undefined reference to `log'
collect2: error: ld returned 1 exit status
Run Code Online (Sandbox Code Playgroud)
但是,如果我替换log(0.0)为log(10.0),那么它可以成功编译.
我不太明白这一点,因为无论它们是否具有数学意义,它们都应该编译 - 没有语法错误.有人能解释一下吗?
以防万一,我的gcc -v输出:
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.8.2-19ubuntu1' --with-bugurl=file:///usr/share/doc/gcc-4.8/README.Bugs --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.8 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.8 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --disable-libmudflap --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64 …Run Code Online (Sandbox Code Playgroud) 可能重复:
gcc:为什么链接数学库需要-lm标志?
一般来说,除了包含头文件之外,为了使用任何数学函数,math.h您必须使用链接器选项-lm进行链接.-l这里将指代用于搜索特定库的链接器选项libm.o.
我的问题是
为什么GCC默认不包含此库?是因为库大量使用数学协处理器,它需要添加额外的代码来初始化浮点初始化(我可能在这里使用错误的术语)?
注意
我刚刚查看了链接http://stackoverflow.com中提到的所有答案.这对我来说没什么意义.归因于三个基本原因
这是一个例子
abhibhat@abhibhat-VirtualBox:~/Projects/GIPL6_2$ ls -1 Test_*|xargs -I{} sh -c "echo {} && echo "-----------------" && cat {}"
Test_withlibm.c
-----------------
#include<stdio.h>
#include<math.h>
int main() {
int i=20;
double output1=pow(2.618033988749895,i);
return 0;
}
Test_withoutlibm.c
-----------------
#include<stdio.h>
#include<math.h>
double Pow(double _X, int _Y) {
double _Z = 1;
for (; _Y; _X *= _X) {
if (_Y & 1) _Z *= _X;
_Y >>= 1;
} …Run Code Online (Sandbox Code Playgroud) 我不知道我是否遗漏了一些明显的东西,但似乎我无法计算C中变量的平方根; sqrt()函数似乎只适用于常量.这是我的代码:
#include <math.h>
#include <stdio.h>
int main()
{
double a = 2.0;
double b = sqrt(a);
printf("%f", b);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
当我运行此程序时,我收到以下错误:
gcc -Wall -o "test2" "test2.c" (in directory: /home/eddy/Code/euler)
/tmp/ccVfxkNh.o: In function `main':
test2.c:(.text+0x30): undefined reference to `sqrt'
collect2: ld returned 1 exit status
Compilation failed.
Run Code Online (Sandbox Code Playgroud)
但是,如果我将sqrt()中的参数替换为常量(例如2.0,(b = sqrt(2.0))),那么它可以正常工作.sqrt()不应该使用变量或其他东西吗?
谢谢您的帮助
我这里有一个示例文件:
#include <stdio.h>
#include <math.h>
int main(){
printf("%f\n", log(10));
}
Run Code Online (Sandbox Code Playgroud)
当我用gcc sample.c -o a它编译它时工作得很好.我可以运行它./a并产生2.302585预期的输出.
然而,当我的文件看起来像这样:
#include <stdio.h>
#include <math.h>
int main(){
double a = 10;
printf("%f\n", log(a));
}
Run Code Online (Sandbox Code Playgroud)
它没有编译gcc sample.c -o a.相反,我必须使用,gcc sample.c -o a -lm以便我可以明显地告诉它"链接数学"...这是我没有真正遵循的地方,为什么我不必在第一个例子中链接数学?它究竟是什么意思必须"链接数学"?自从我使用C编译器以来已经有一段时间了,所以如果这是一个糟糕的问题,请原谅我.
换句话说,静态(=文件范围)全局变量可以从一个下划线开始,而不会产生C实现的名称冲突的可能性吗?
https://www.gnu.org/software/libc/manual/html_node/Reserved-Names.html 表示"...保留名称包括以下划线开头的所有外部标识符(全局函数和变量)('_' )......(强调我的).
我注意到Linux内核启动的功能可能不应该直接用双下划线调用.
我发现这个概念很有用,而且我发现它比识别"私有"标识符_(_)something更容易阅读something_,但我理解(?)双下划线邀请名称与C实现冲突.
全球性,静态性 _variables和_functions安全性?
在FreeBSD上10.1使用Clang版本3.4.1
现在我已经看到其他线程询问如何使用pow()进行编译,但我还没有看到有这个问题的线程.举个例子:
#include <math.h>
#include <stdio.h>
int main()
{
float result;
result = pow(2,3);
printf("%d", result);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
现在使用pow(),我需要发出clang参数-lm.
cc -lm -o name name.c
但是,更换pow(2,3)用sqrt(5);,我可以编译cc -o name name.c.如果它们都使用math.h,那么为什么pow()需要链接到库?方面没有:安装gcc进行测试,我根本不需要使用-lm.