【发布时间】:2016-05-07 02:29:51
【问题描述】:
为简单起见,假设我使用的是 32 位 little-endian 处理器并声明了以下 4 字节缓冲区:
unsigned char buffer[] = { 0xab, 0xcd, 0xef, 0x46 };
假设我的目标是将缓冲区中的每个字节按位左移 4 位。也就是说,我想将缓冲区值转换为:
{ 0xbc, 0xde, 0xf4, 0x60 }。要执行这样的转换,可以编写如下代码:
for (int i = 0; i < 3; ++i)
{
buffer[i] <<= 4;
buffer[i] |= (buffer[i + 1] >> 4);
}
buffer[3] <<= 4;
虽然这可行,但我更愿意使用处理器的原生 32 位寄存器同时移动所有 4 个字节:
unsigned char buffer[] = { 0xab, 0xcd, 0xef, 0x46 };
unsigned int *p = (unsigned int*)buffer; // unsigned int is 32 bit on my platform
*p <<= 4;
上面的 sn-p 成功地执行了一个转变,但不是我正在寻找的方式。看来,由于我将缓冲区转换为无符号整数,因此使用值 0x46efcdab(而不是 0xabcdef46)加载(小端序)寄存器。因此,执行 4 位左移会导致 0xb0dafc6e 而不是 0xbcdef460。
除了在移位之前交换字节(例如htonl 等),还有什么技巧可以按照我正在寻求的方式有效地移位字节吗?
提前感谢您的见解。
【问题讨论】:
-
@user3386109,是的,它是 x86
-
那我同意 nneonneo 的回答。编译器会将
htonl实现为一条指令(在适当的优化级别)。不知道最低限度是多少,但-O3绝对有效。 -
如果你使用了 C 提供的固定类型,你可以避免一大堆假设
unsigned在你的平台上有多宽,等等。参见stdint.h,它们就是这样为了。如果你想序列化数据,使用适当的位移/屏蔽,而不是强制转换,你的代码会调用未定义的行为.. -
@Olaf,您能否详细说明我的代码如何调用未定义的行为?
-
对于初学者来说,它可能会出现对齐问题。而且你违反了有效类型规则(又名严格别名)。
标签: c bit-manipulation bit-shift