C Math sqrt和Gcc -lm选项 [英] C Math sqrt and Gcc -lm option

查看:112
本文介绍了C Math sqrt和Gcc -lm选项的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

一些善良的灵魂可以帮助我理解为什么我必须使用-lm gcc选项(像这样
gcc main.c -o main -lm)在情况(1)中没有,而在情况(2)中没有?

Could some good soul help me understand why do I have to use -lm gcc option (like so
gcc main.c -o main -lm) in case (1) and do not have in case (2)?

案例(1)

#include <math.h>
int main() {
  float x = 4;
  sqrt(x);
  return 0;
}

案例(2)

#include <math.h>
int main() {
  sqrt(4);
  return 0;
}

我正在使用带有gcc的Ubuntu 16.04. 我知道为什么我应该使用-lm,但是我不知道为什么没有它的情况(2).

I'm using Ubuntu 16.04, with gcc. I know why I should use -lm, but I don't know why the case (2) works without it.

推荐答案

让我们看一下几个函数.这是第一个:

Let's have a look at a couple of functions. Here's the first one:

#include <math.h>

double func(double num) {
  return sqrt(num);
}

使用gcc -O3 -c so.c进行编译,并使用objdump -d so.o进行反汇编:

Compile with gcc -O3 -c so.c and disassemble with objdump -d 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   

因此,我们有许多FPU寄存器操作和一个调用.让我们尝试看看该调用所调用的内容.运行nm so.o:

So we have a bunch of FPU register operations, and a call. Let's try to see what that call calls. Run nm so.o:

0000000000000000 T func
                 U sqrt

因此,我们正在定义(T)一个名为"func"的函数,并导入(U)一个名为sqrt的符号.最终的程序必须与-lm链接,因为实际上是在其中定义sqrt的地方.

So we are defining (T) a function called "func", and importing (U) a symbol called sqrt. The eventual program will have to be linked with -lm, as that's where sqrt is actually defined.

现在让我们尝试第二个功能:

Now let's try a second function:

#include <math.h>

double func() {
  return sqrt(4);
}

再次使用gcc -O3 -c so.c进行编译,并使用objdump -d so.o进行反汇编:

Again, compile with gcc -O3 -c so.c and disassemble with objdump -d so.o:

0000000000000000 <func>:
   0:   f2 0f 10 05 00 00 00    movsd  0x0(%rip),%xmm0        # 8 <func+0x8>
   7:   00 
   8:   c3                      retq   

没有FPU寄存器操作.没有函数调用.让我们用nm so.o验证:

No FPU register operations. No function calls. Let's verify with nm so.o:

0000000000000000 T func
0000000000000000 r .LC0

是的.不导入符号.

如果省略#include <math.h>,您将了解这里发生的事情:

You get a hint of what's going on here if you omit #include <math.h>:

$ gcc -O3 -g -c so.c
so.c: In function ‘func’:
so.c:2:10: warning: incompatible implicit declaration of built-in function ‘sqrt’
   return sqrt(4);
          ^

sqrt是内置函数.编译器不会将其视为某些不透明的构造.它了解它的作用.在第二种情况下,编译器理解它不需要在运行时对函数进行调用.它知道编译期间的答案.它只是将答案放在返回寄存器中,并称之为一天.由于运行时不包含对sqrt的调用,因此无需与-lm链接.

sqrt is a built-in function. The compiler does not treat it as some opaque construct. It understands what it does. In the second case, the compiler understands that it does not need to place a call to the function at run time. It knows what the answer is during compilation. It simply places the answer in the return registers and calls it a day. Since the run time does not contain a call to sqrt, there is no need to link with -lm.

这篇关于C Math sqrt和Gcc -lm选项的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆