我正在从连接到树莓(手臂)的传感器上读取一个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
也许我已经回答了我自己的问题,但如果有人可以评价,那就太好了。这不是我第一次欺骗自己。
答案 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