gcc编译含math.h程序的奇怪现象(并非未添加-lm)

时间:2021-09-29 04:23:18

gcc编译含math.h程序的奇怪现象(并非未添加-lm)

      Powered by lihux @ ustc    

    最近学习linux下编程时发现一个小问题:
  一个最简单的main.c程序
  #include<math.h>
  #include<stdio.h>
  int main()
  {
  double a = 4;
  sqrt(a);
  return 0;
  }

  如果使用gcc而非g++编译的话,直接使用命令:
  #gcc -o a main.c
  编译会提示未找到sqrt的定义,这个是因为缺少了“-lm”:必须要显示的调用libm.so动态库;
  但是现在,有一种情况直接通过
  #gcc -o a main.c
  来编译而不报错的情况:即把sqrt(a)改成sqrt(4)!

在CSDN上请教了高手之后说是编译器直接计算sqrt(4)了,可以看汇编代码,本该调用函数的地方是一个mov ,而未使用libm.so中的sqrt()函数,自然也就可以编译通过了。于是我就通过设计一个测试程序,然后编译成汇编文件.s,查看:

/************************************
void math()
{
  double a = sqrt(4.23);
}


void matha()
{
  double a = 4.23;
  sqrt(a);
}
/************************************

编译成汇编文件后得到对应的代码分别为:

/***************************************
.globl math
.type math, @function
math:
pushl %ebp
movl %esp, %ebp
subl $16, %esp
fldl .LC0
fstpl -8(%ebp)

leave
ret
.size math, .-math


.globl matha
.type matha, @function
matha:
pushl %ebp
movl %esp, %ebp
subl $40, %esp
fldl .LC2
fstpl -16(%ebp)
fldl -16(%ebp)
fsqrt

fucomp %st(0)
fnstsw %ax
sahf
jp .L6
je .L5
.L6:
fldl -16(%ebp)
fstpl (%esp)
call sqrt

fstp %st(0)
.L5:
leave
ret
.size matha, .-matha
/*****************************************

代码虽然不是全懂,但一经对比就会发现,sqrt(a)的汇编代码确实是有调用:“call sqrt”,而sqrt(4.23)则没有。由于gcc 相比于g++无法自动连接C++库,使用gcc编译必须加“-lm”,而g++则不必,所以我们平时编译程序的时候应优先选择g++。

     问题找到了之后,不禁感慨,居然是聪明的编译器在其中做了手脚,没有经验的人怎可能看的出来呢?看来,内功还要继续练习啊。