math.h -lm随记(一)
最近可能随手会记很多C/C++语法相关的东西,都是随手记的,如果后续有空可能会整理成文章。
1.关于gcc的lm编译选项:
观察易知,像stdio.h,stdlib.h或者math.h之类的头文件,包含的都是函数的声明而非定义。(关于声明和定义,详见之前《浅谈指针》的文章系列)而真正的函数定义,都是包含在库中的。在gcc中,C语言的库涉及到的有libc和libm,后缀名是.so。
由于历史原因,早期的浮点数运算开销很大,因此ANSI C中特地将libm.so(m是math的首字母)独立开来,如果要使用libm.so的函数必须显式地指定编译选项-lm。一般而言很多开发环境的默认选项中都有这个-lm。
2.g++是否需要-lm?
答案是否定的。g++所使用的运行库libstdc++在链接时必须包含libm才能正常运行,因此无需显式指定lm,编译时会自动包含。就像stdio.h或者stdlib.h中的库libc会自动包含一样。
3.关于一些编译优化
在此处借助https://godbolt.org/进行反汇编的实验。使用gcc -s的结果亦可,应该不会差异太大。
int main(){
auto x=pow(2,3);
}
这段代码所反汇编的结果是:
main:
push rbp
mov rbp, rsp
mov DWORD PTR [rbp-4], 8
mov eax, 0
pop rbp
ret
可以看到当pow的两个参数都为常数的时候,根本没有产生函数调用。这种情况下也是不用指定-lm就能正常运行的。
而如果是变量的话:
#include<math.h>
int main(){
auto a=2.5,b=3.125;
auto x=pow(a,b);
}
main:
push rbp
mov rbp, rsp
sub rsp, 16
mov DWORD PTR [rbp-4], 2
mov DWORD PTR [rbp-8], 3
pxor xmm0, xmm0
cvtsi2sd xmm0, DWORD PTR [rbp-8]
pxor xmm2, xmm2
cvtsi2sd xmm2, DWORD PTR [rbp-4]
movq rax, xmm2
movapd xmm1, xmm0
movq xmm0, rax
call pow
cvttsd2si eax, xmm0
mov DWORD PTR [rbp-12], eax
mov eax, 0
leave
ret
此时才有pow的调用。(里面还出现了一些浮点数特殊指令,这里我也不详细介绍了,只能说现在汇编语言的各种硬件级优化是越做越高了,感觉甚至有点高级语言的感觉了)
先写这点,后续有空补(二)章