我发现在一些答案中,他们建议使用
lower = (some_var << 32) >> 32;
但是我测试后发现以下代码更快:
lower = some_var & 0xffffffff;
那么哪个更好?前者在某些情况下是否更安全或编译器优化后更快?
我发现在一些答案中,他们建议使用
lower = (some_var << 32) >> 32;
但是我测试后发现以下代码更快:
lower = some_var & 0xffffffff;
那么哪个更好?前者在某些情况下是否更安全或编译器优化后更快?
使用 &
进行掩码更好:
&
对于有符号和无符号的 some_var
都是可靠的,而将负数右移位会产生一个实现定义的结果:E1 >> E2 的值为 E1 向右移动 E2 位。[...] 如果 E1 具有有符号类型并且具有负值,则产生的值为实现定义。
掩码的一个缺点是相对容易意外地拥有 7 或 9 个 F
,而在 32
中的打字错误则很明显:还有其他方法可以生成掩码值,例如 (1LL<<32)-1
,或者 hackish 但某种程度上优雅的 uint32_t(-1)
。
当然,如果 lower
是 uint32_t
,而 some_var
是 uint64_t
,你可以让转换隐式进行,这样优化器甚至不需要意识到按位与在赋值之前就可以被删除,但这可能会给你一个编译器警告,你可以通过以下方式消除它...
uint32_t lower = static_cast<uint32_t>(some_var);
uint64_t
时有用,或者当掩码不是应用于32个最低有效位时。使用AND进行掩码处理更好,因为它不依赖于值的符号。
但是获取低32位最有效的方法是将其赋值给一个32位变量。
uint64_t u = 0x1122334455667788;
uint32_t n;
n = static_cast<uint32_t>(u); // 0x55667788
lower = some_var & 0xffffffff;
另一种形式可能会产生不必要的移位。typedef union {
int64 QWORD;
int32 DWORD[2];
} overlapper64;
overlapper someVariable;
someVariable.QWORD;
int32 myVar32 = someVariable.DWORD[0];
根据平台/编译器,重叠发生的顺序可能会有所不同。 一定要在您特定的平台上进行测试。 在C中,我使用一堆特定于平台的#ifdef来自动控制顺序。
除了其他人说的,根据你使用的编译器,第二个选项可能更快,因为如果没有进行优化,第一个选项将被实现为2个CPU指令,而第二个选项只有1个CPU指令。这可能是你观察到使用第二个选项提高性能的原因。
我认为两种方法都很好。然而,使用位运算符会是一种更好的(不确定是否有性能差异)方法,因为标准规定:
6.5.7 位移操作符
4 E1 << E2 的结果是将 E1 左移 E2 位;空出的位用零填充。如果 E1 具有无符号类型,则结果的值为 E1 × 2E2,对结果类型可表示的最大值加一取模后的余数。如果 E1 具有带符号类型和非负值,并且 E1 × 2E2 可以在结果类型中表示,则该值就是结果;否则,行为未定义。
some_var
的确切类型是什么?具体来说,它是无符号的吗? - Suma