哪种方式更好地获得64位整数的低32位

时间:2015-03-20 05:51:44

标签: c++

我发现在某些答案中他们建议使用

lower = (some_var << 32) >> 32;

但我测试后发现以下内容更快:

lower = some_var & 0xffffffff;

哪个更好?在编译器优化后,前者在某些情况下更安全还是更快?

5 个答案:

答案 0 :(得分:7)

使用&屏蔽更好:

  • &对于有符号和无符号some_var是可靠的,而向右移位为负数会产生实现定义结果:
  

E1的值&gt;&gt; E2是E1右移E2位位置。 [...]如果E1具有有符号类型和负值,则结果值是实现定义的。

  • 在我所知道的每个CPU上(Z80,6502C,x86,68000,UltraSparc),按位AND是单CPU指令,需要一个时钟周期......它不太可能更慢或占用更多字节机器代码比你提到的位移方法,尽管编译器可能会优化它到按位AND。

屏蔽的一个缺点是,相对容易意外地有7或9 F s,而32中的拼写错误很明显:有其他方法可以生成屏蔽值,例如: (1LL<<32)-1,或者是hackish,但有些优雅uint32_t(-1)

当然,如果loweruint32_tsome_var uint64_t,您可以让转换隐含,因此优化工具甚至不需要实现bitwise-AND可以在赋值之前删除,但是这可能会给你一个编译器警告,你可以用它来沉默...

uint32_t lower = static_cast<uint32_t>(some_var);

当分配给另一个uint64_t时,或者当掩码不是所有32个最低有效位时,屏蔽主要是有用的。

答案 1 :(得分:5)

使用AND进行屏蔽更好,它不依赖于值的签名。

但是,采用低32位的最有效方法是将其分配给32位变量。

uint64_t u = 0x1122334455667788;
uint32_t n;

n = static_cast<uint32_t>(u);  // 0x55667788

与逐位AND的不同之处在于CPU只是在不执行任何逻辑操作的情况下占用较低的部分。

如果你有一个32位CPU,它只会忽略存储在第二个寄存器或存储器位置的上限值。

如果你有一个64位CPU,它有一条指令将32位值扩展(无符号)为64位值。

答案 2 :(得分:1)

一个好的优化器会在两种情况下生成相同的代码。对我来说,这是最直接的方法:lower = some_var & 0xffffffff;另一种形式可能会产生不必要的移位。

当我想绝对确定编译器不会搞砸时,我有时会使用union来重叠变量。

例如:

typedef union {
    int64 QWORD;
    int32 DWORD[2];
} overlapper64;

overlapper someVariable;

然后将其作为:

访问
someVariable.QWORD;

int32 myVar32 = someVariable.DWORD[0];

根据平台/编译器的不同,重叠的顺序可能会有所不同。 请务必在您的特定平台上进行测试。 在C中,我使用一堆特定于平台的#ifdefs来自动控制订单。

答案 3 :(得分:1)

添加其他人所说的,基于你使用第二个选项的编译器可能会更快,因为如果没有优化,第一个选项实现为2个cpu指令,而第二个选项是一个cpu指令。这可能是您使用第二个选项观察性能提升的原因。

答案 4 :(得分:0)

我认为两者都同样好。但是,如标准所示,使用按位运算符会更好(不确定是否存在性能差异)方法:

  

6.5.7按位移位运算符

     

4&lt;&lt;&lt;&lt;&lt;&lt; E2是E1   左移E2位位置;腾空   位用零填充。如果E1有   无符号类型,值的   结果是E1×2E2,减少模1   超过最大值   在结果类型中可表示。如果   E1具有签名类型和非负   值,E1×2E2是可表示的   在结果类型中,那就是   结果价值;否则,   行为未定义。