我只是想知道是否有人知道按位AND和OR以及对常量进行操作的按位移位是否会被编译器预先计算为常数值。
例如int Foo = Bar / ( 1 << 12 )
我这样做而不是Bar >> 12
的原因是,如果Bar是负值,它会下降到-1而不是零。
答案 0 :(得分:4)
&#34;我只是想知道是否有人知道按位AND和OR以及对常量进行操作的按位移位是否会被编译器预先计算为常数值。&#34;
是的
( 1 << 12 )
部分将在编译时进行评估。
它实际上和写作一样
int Foo = Bar / 4096;
答案 1 :(得分:1)
即使是最蹩脚的编译器也会像这样进行简单的常量折叠。真的,你可能会在大学的编译器课程中实现它,这就是它的水平。
编译器偶尔会对我们人类做一些看似愚蠢的事情,通常是无法检测到的“全局”事物。但是编译器在这种类型的东西上很棒,它只需要一些本地可用的信息,它可以查看代码内部表示的一小部分,并将其与一些已知模式相匹配。两个众所周知的例子是恒定折叠和强度降低。
所以你真的可以期待更多,这种分裂应该消失。有一个众所周知的(在编译器构建圆圈中)通过一个常数将除法转换为(粗略地,忽略细节)乘法和移位,并且有一个更简单的分配方法用于已知的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个非正数,使它们以正确的方式进行。
答案 2 :(得分:0)
在C ++ 11中,您可以使用&#39; constexpr&#39;强制编译器在编译时以常量表达式进行计算
答案 3 :(得分:0)
通常,如果您想知道编译器是否可以在编译时计算常量整数值(不使用constexpr
),请尝试使用计算值作为C数组的大小。
int arr[Bar / ( 1 << 12 )];
如果它编译,你知道它成功了,因为C数组大小在编译时必须是常量。