C++:别再背 const 和 constexpr 的区别了

举报
七昂的技术之旅 发表于 2024/06/16 22:56:21 2024/06/16
【摘要】 从底层汇编指令的角度体会了一下什么是constexpr的编译期计算,总之,const用于限定变量运行期的“不可变性”;constexpr用于定义常量、常量表达式或常函数,实现编译期计算。

前言

最开始看const和constexpr的区别,知道const用来限定只读语义,constexpr用来定义常量语义。只不过“只读”和“常量”的含义,略微有点抽象。其实前者就是指运行期的“不可变性”,后者就是用来实现编译期计算。那么就计算机底层而言,二者到底会有什么不同呢?下面就从汇编指令来直观体会一下什么是constexpr的“编译期计算”,也顺便理解理解“运行时”和“编译时”、“动态”和“静态”这些名词。

image.png

constexpr 常量

const和constexpr都可以定义编译期常量。

  • 定义变量a

void test(){
    int a = 1;
    int b = a + 1;
}

对应汇编指令为,

test():
        push    rbp
        mov     rbp, rsp
        mov     DWORD PTR [rbp-4], 1     # 定义a = 1
        mov     eax, DWORD PTR [rbp-4]   # 把a存入寄存器eax
        add     eax, 1                   # 执行eax += 1
        mov     DWORD PTR [rbp-8], eax   # 把eax存入b
        nop
        pop     rbp
        ret

以上包含了计算b的过程,需要从eax寄存器读取b的值。

  • 定义constexpr/const常量a
void test(){
    constexpr int a = 1;
    int b = a + 1;
}

对应汇编指令为:

test():
        push    rbp
        mov     rbp, rsp
        mov     DWORD PTR [rbp-4], 1      # 定义a = 1
        mov     DWORD PTR [rbp-8], 2      # 定义b = 2
        nop
        pop     rbp
        ret

与未使用constexpr相比,少了两条指令,采用的是立即数寻址的方式,直接将2存入了b中。

constexpr 函数

  • 定义不带constexpr的函数

int square(int num) {
    return num * num;
}

int main(){
    int b = 1 + square(1);
    return 0;
}

对应汇编指令为:

square(int):
        push    rbp
        mov     rbp, rsp
        mov     DWORD PTR [rbp-4], edi
        mov     eax, DWORD PTR [rbp-4]
        imul    eax, eax
        pop     rbp
        ret
main:
        push    rbp
        mov     rbp, rsp
        sub     rsp, 16
        mov     edi, 1                  # 把参数1存入寄存器edi
        call    square(int)             # 调用square函数
        add     eax, 1                  
        mov     DWORD PTR [rbp-4], eax
        mov     eax, 0
        leave
        ret

在运行时会调用square函数进行计算。

  • 定义constexpr函数
constexpr int square(int num) {
    return num * num;
}

int main(){
    int b = 1 + square(1);
    return 0;
}

对应汇编指令为:

main:
        push    rbp
        mov     rbp, rsp
        mov     DWORD PTR [rbp-4], 2         # 把2存入b
        mov     eax, 0
        pop     rbp
        ret

当直接传入常数2到 square函数,与未使用constexpr相比,少了多条汇编指令,没有了函数调用的指令,直接将2存入了b中。

测试程序:https://compiler-explorer.com/z/5TnMTrrqr

总结

以上从底层汇编指令的角度体会了一下什么是constexpr的编译期计算,总之,const用于限定变量运行期的“不可变性”;constexpr用于定义常量、常量表达式或常函数,实现编译期计算。

如果本文内容对您有帮助,请点赞关注,鼓励我持续创作;如果对内容有疑问或者有更好的建议,欢迎在评论区留言。

希望进一步深入学习C++的朋友可以关注我的公众号:七昂的技术之旅。关注后回复"C++"送你一份学习资料。

image.png

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。