【问题标题】:Do bitwise operations resolve to constant values是否按位运算解析为常量值
【发布时间】:2014-11-30 12:08:26
【问题描述】:

我只是想知道是否有人知道编译器是否将按位 AND 和 OR 以及对常量进行的按位移位预先计算为常量值。

例如int Foo = Bar / ( 1 << 12 )

我这样做而不是 Bar >> 12 的原因是,如果 Bar 是负值,它会下降到 -1 而不是零。

【问题讨论】:

  • 任何体面的编译器都可以在编译期间计算常量表达式(即仅包含常量值的表达式)作为优化。不仅是按位表达式,还有其他表达式。

标签: c++ variables bit-manipulation constants


【解决方案1】:

“我只是想知道是否有人知道按位 AND 和 OR 以及对常量进行的按位移位是否被编译器预先计算为常量值。”

是的

( 1 << 12 )

部分将在编译时评估。

实际上和写作一样

int Foo = Bar / 4096;

【讨论】:

    【解决方案2】:

    即使是最蹩脚的编译器也会像这样进行简单的常量折叠。真的,你可能会在大学的编译器课程中实现它,这就是它的水平。

    编译器偶尔会做一些对我们人类来说似乎很愚蠢的事情,通常是它无法检测到的“全局”事情。但是编译器非常擅长这种类型的事情,它只需要一些本地可用的信息,它可以查看代码的一小部分内部表示并将其与某些已知模式匹配。两个众所周知的例子是恒定折叠和强度降低。

    所以你真的可以在这里期待更多,那个部门应该消失了。有一个众所周知的(无论如何在编译器构建圈子中)配方可以将除以常数转换为(粗略地,忽略细节)乘法和移位,还有一个更简单的除以已知的二的幂的配方(这个案例!)

    GCC on -O2 变成了这个:

    int foo(int x)
    {
        return x / (1 << 12);
    }
    

    进入这个:

    lea eax, [rdi+4095]
    test    edi, edi
    cmovns  eax, edi
    sar eax, 12
    ret
    

    没有左移,没有除法。它将 4095 添加到非正数以使它们以正确的方式四舍五入。

    【讨论】:

    • 嗯,也许没有左移,但对我来说似乎是右移sar eax 12...+1 还是来自我。
    • @doc 好吧,是的,它必须以某种方式划分
    【解决方案3】:

    在 C++11 中,可以使用 'constexpr' 强制编译器在编译时以常量表达式进行计算

    【讨论】:

      【解决方案4】:

      一般来说,如果您想知道您的编译器是否可以在编译时计算一个常量整数值(不使用constexpr),请尝试使用计算的值作为 C 数组的大小。

      int arr[Bar / ( 1 << 12 )];
      

      如果它编译了,你就知道它成功了,因为 C 数组的大小在编译时必须保持不变。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-03-22
        • 2023-03-23
        • 2013-07-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-03-26
        相关资源
        最近更新 更多