位操作OR与添加

时间:2015-06-28 08:25:46

标签: c++ c bitwise-operators

我正在从连接到树莓(手臂)的传感器上读取一个uint16。我通过以下方式将数据从little endian转换为big endian:

// result = 0A 0B
// 0B 00 | 00 0A
(result << 8) | (result >> 8);

之后0A 0B为0B 0A。

但我也看到有人使用这个:

(result << 8) + (result >> 8);

使用添加有什么好处吗?我的猜测是,没有什么优势,只是有点慢。

例如,对两个数字求和有很大的不同:

EF10 = 0FF0 + 00FF != 0FF0 | 00FF = 0FFF

也许我已经回答了我自己的问题,但如果有人可以评价,那就太好了。这不是我第一次欺骗自己。

2 个答案:

答案 0 :(得分:3)

使用按位或|清楚地说明了读取代码的意图是什么,这是重要的一点。

我对两种方法之间的速度差异感到惊讶。

更好的是:

x = (x << 8) | (x >> 8);

因为左边部分不需要掩码(因为输入的比特是零)。

如果是有符号整数,则在对负值执行右移操作时所涉及的是依赖于实现的,因此可移植代码应该使用

x = (x << 8) | ((x >> 8) & 0xFF);

表明请求了字节交换操作。

答案 1 :(得分:2)

如果组合的位不重叠(换句话说,左侧的掩码对于由右侧设置的所有位都为零),则没有区别(或优势,至少在现代处理器上没有)手边,反之亦然)

此处显示的代码:

// result = 0A0B0C0D 0E0F0A0B
// 0E0F0A0B 00000000 | 00000000 0A0B0C0D
((result << 8) & 0xFF00) | (result >> 8);

有点令人困惑 - 评论似乎暗示它是32位值,但计算意味着16位result

如果您执行以下操作,您将获得不同的结果:

value |= 128;

VS

value += 128;

value已经设置了第7位时。

请注意,至少在clang中:

#include <cstdint>

uint32_t func1(uint32_t x)
{
    return (x >> 8) | ((x << 8) & 0xFF000000);
}

uint32_t func2(uint32_t x)
{
    return (x >> 8) + ((x << 8) & 0xFF000000);
}

生成完全相同的代码:

_Z5func1j:                              # @_Z5func1j
    movl    %edi, %eax
    shrl    $8, %eax
    shll    $8, %edi
    andl    $-16777216, %edi        # imm = 0xFFFFFFFFFF000000
    leal    (%rdi,%rax), %eax
    retq

_Z5func2j:                              # @_Z5func2j
    movl    %edi, %eax
    shrl    $8, %eax
    shll    $8, %edi
    andl    $-16777216, %edi        # imm = 0xFFFFFFFFFF000000
    leal    (%rdi,%rax), %eax
    retq