C数学sqrt和Gcc-lm选项
一些善良的灵魂能帮助我理解为什么我必须使用C数学sqrt和Gcc-lm选项,c,gcc,C,Gcc,一些善良的灵魂能帮助我理解为什么我必须使用-lmgcc选项(像这样 gcc main.c-o main-lm)在第(1)种情况下,而在第(2)种情况下没有 案例(1) #包括 int main(){ 浮动x=4; sqrt(x); 返回0; } 案例(2) #包括 int main(){ sqrt(4); 返回0; } 我正在使用Ubuntu 16.04和gcc。 我知道为什么我应该使用-lm,但我不知道没有它为什么案例(2)可以工作。让我们看看几个函数。这是第一个: #include &l
-lm
gcc选项(像这样gcc main.c-o main-lm
)在第(1)种情况下,而在第(2)种情况下没有
案例(1)
#包括
int main(){
浮动x=4;
sqrt(x);
返回0;
}
案例(2)
#包括
int main(){
sqrt(4);
返回0;
}
我正在使用Ubuntu 16.04和gcc。
我知道为什么我应该使用
-lm
,但我不知道没有它为什么案例(2)可以工作。让我们看看几个函数。这是第一个:
#include <math.h>
double func(double num) {
return sqrt(num);
}
所以我们有一堆FPU寄存器操作和一个调用。让我们试着看看那叫什么。运行nm so.o
:
0000000000000000 <func>:
0: f2 0f 51 c8 sqrtsd %xmm0,%xmm1
4: 66 0f 2e c9 ucomisd %xmm1,%xmm1
8: 7a 05 jp f <func+0xf>
a: 66 0f 28 c1 movapd %xmm1,%xmm0
e: c3 retq
f: 48 83 ec 08 sub $0x8,%rsp
13: e8 00 00 00 00 callq 18 <func+0x18>
18: 48 83 c4 08 add $0x8,%rsp
1c: c3 retq
0000000000000000 T func
U sqrt
0000000000000000 <func>:
0: f2 0f 10 05 00 00 00 movsd 0x0(%rip),%xmm0 # 8 <func+0x8>
7: 00
8: c3 retq
0000000000000000 T func
0000000000000000 r .LC0
因此,我们正在定义(T
)一个名为“func”的函数,并导入(U
)一个名为sqrt
的符号。最终的程序必须与-lm
链接,因为sqrt
实际上就是在这里定义的
现在,让我们尝试第二个函数:
#include <math.h>
double func() {
return sqrt(4);
}
没有FPU寄存器操作。没有函数调用。让我们用nmso.o
进行验证:
0000000000000000 <func>:
0: f2 0f 51 c8 sqrtsd %xmm0,%xmm1
4: 66 0f 2e c9 ucomisd %xmm1,%xmm1
8: 7a 05 jp f <func+0xf>
a: 66 0f 28 c1 movapd %xmm1,%xmm0
e: c3 retq
f: 48 83 ec 08 sub $0x8,%rsp
13: e8 00 00 00 00 callq 18 <func+0x18>
18: 48 83 c4 08 add $0x8,%rsp
1c: c3 retq
0000000000000000 T func
U sqrt
0000000000000000 <func>:
0: f2 0f 10 05 00 00 00 movsd 0x0(%rip),%xmm0 # 8 <func+0x8>
7: 00
8: c3 retq
0000000000000000 T func
0000000000000000 r .LC0
是的。不导入符号
如果省略#include
,您会得到这里发生的事情的提示:
sqrt
是一个内置函数。编译器不会将其视为某种不透明的构造。它知道自己在做什么。在第二种情况下,编译器知道它不需要在运行时调用函数。在编译过程中,它知道答案是什么。它只需将答案放在报税表中,并称之为一天。由于运行时不包含对sqrt
的调用,因此不需要与-lm
链接,因为编译器知道sqrt(4)
是2。在第一种情况下,尝试一下gcc-O3 main.c-o main,看看它是否有效非常感谢你!