我建议您不要考虑编译器后端可能会做什么,如果您不使用优化,那么没关系,如果您使用优化,那么任何好的编译器都会在很少的指令中做正确的事情尽可能为您的编译目标。
考虑它在语言中的语义含义。例如,如果 flags 是 typeuint64_t
并且BIT_NUMBER
大于 31,那么只有 2nd 形式可能会执行您想要的操作。原因是(BIT_MASK << BIT_NUMBER)
它将被评估为int
,可能是 32 位,并且由于BIT_NUMBER
大于 31 将评估为零,因此整个事物在 AND 之后将产生零。另一方面,(flags >> BIT_NUMBER)
将被评估为 64 位表达式(因为标志是 64 位),并且在执行 AND 之前将被正确移位。
有关 Clang 编译器的有趣讨论,请参阅Clang: Defending C++ from Murphy's Million Monkeys这将向您展示当今编译器可能对语义理解的深度,特别是查看21:25
我在上面提到的 C++ 整数算术规则的细微差别的分钟. 这是演讲中使用的示例
static const long long DiskCacheSize = 8 << 30; // 8 Gigs
Clang gives:
% clang++ -std=c++11 -fsyntax-only overflow.cpp
overflow.cpp:1:42: warning: signed shift result (0x200000000) requires 35
bits to represent, but 'int' only has 32 bits [-Wshift-overflow]
static const long long DiskCacheSize = 8 << 30; // 8 Gigs
~ ^ ~~
最近,我惊讶地发现 gcc 和 Java JIT 编译器足够聪明,可以理解一组移位、掩码和 OR 本质上是对 32 位量进行旋转,例如,将生成旋转指令,请参阅按位旋转是否比当前 Intel CPU 上的移位慢?. 这些天编译器非常好。