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的调用。(里面还出现了一些浮点数特殊指令,这里我也不详细介绍了,只能说现在汇编语言的各种硬件级优化是越做越高了,感觉甚至有点高级语言的感觉了)

先写这点,后续有空补(二)章

posted @ 2022-09-03 20:50  计算机知识杂谈  阅读(132)  评论(0编辑  收藏  举报