鲲鹏社区首页
中文
注册
开发者
我要评分
获取效率
正确性
完整性
易理解
在线提单
论坛求助

利用constexpr将计算从运行时提前至编译时

【说明】 C++11开始引入了constexpr标识符,开发者可以通过该标识符告诉编译器,被标识的变量或函数在符合条件时会尽量在编译时求值。这样做可以提升程序运行时的效率,但会以增加编译时间为代价。constexpr对被标识的变量和函数有非常多的限制条件,并且对于不同的C++标准来说,限制条件又有所不同。对于列举这些不同标准下的限制规则,超出了本指南的范畴,请参考C++语言标准。

【注意事项】 不涉及

【案例】

优化前
long int Fib(int n)
{
    return (n <= 1) ? n : Fib(n-1) + Fib(n-2);
}

int Func(int a)
{
    long int res = Fib(30);
    return a + res;
}
以Arm GCC 7.3为例,编译器开-O2优化,生成的汇编代码如下:
Fib(int):
        cmp     r0, #1
        push    {r4, r5, r6, r7, r8, lr}
        mov     r5, #0
        ble     .L2
        sub     r7, r0, #2
        bic     r3, r7, #1
        sub     r6, r0, #3
        sub     r6, r6, r3
        sub     r4, r0, #1
.L3:
        mov     r0, r4
        bl      Fib(int)
        sub     r4, r4, #2
        cmp     r4, r6
        add     r5, r5, r0
        bne     .L3
        and     r0, r7, #1
.L2:
        add     r0, r5, r0
        pop     {r4, r5, r6, r7, r8, pc}
Func(int):
        push    {r4, lr}
        mov     r2, #29
        mov     r4, r0
        mov     r1, #0
.L9:
        mov     r0, r2
        bl      Fib(int)
        sub     r2, r2, #2
        cmn     r2, #1
        add     r1, r1, r0
        bne     .L9
        add     r0, r4, r1
        pop     {r4, pc}

说明:可以看出res的计算是调用了fib(30)在运行时得出的。

优化后:为fib()加上constexpr标识符来使编译器在编译器为fib(30)求值,代码如下:
constexpr long int Fib(int n)
{
    return (n <= 1) ? n : Fib(n-1) + Fib(n-2);
}

int Func(int a)
{
    constexpr long int res = Fib(30);
    return a + res;
}
以Arm GCC 7.3为例,编译器开-O2优化,生成的汇编代码如下:
Func(int):
        add     r0, r0, #831488
        add     r0, r0, #552
        bx      lr

fib(30)的结果831488,在编译期就被求值,fib(30)在运行时直接使用了编译器计算出的运行时常量值。