一、问题描述
将一个字节8位7~0位,按照位反转,即7位与0位交换,6为与1位交换,5为与2位交换,4为与3位交换,举例为,10101011b=0xAB,按位反转,变为11010101b=0xD5。
二、思路解析
常规做法是,定义一个新的变量,将原值的每一位取出,倒序赋值给新的变量。但实际更高效的做法,只需要用到位操作。
整体思路是,既然是将一个字节的8位数进行高低位互换,则先将高4位与低4位互换,这样原本在字节前面的换到了后面,后面的换到了前面;同理,再把高4位中的高2位、低2位互换,这样离目标又近了一步,依次交换,即可实现字节反转。
以前述的10101011b=0xAB为例,说明思路的步骤。如下表,
步骤 | 原数值 | 操作 | 结果 |
---|---|---|---|
1 | 1010 1011 | 交换高4位与低4位 | 1011 1010 |
2 | 1011 1010 | 交换高4位中的高2位、低2位;交换低4位中的高2位、低2位 | 1110 1010 |
3 | 1110 1010 | 交换每2位中的高位、低位 | 1101 0101 |
三、程序代码
根据思路写出程序,需要用到一些位操作的技巧:
1.一个字节,将字节左移4位,则低4位变为高4位,新字节的低4位为0;将字节右移4位,则高4位变为低4位,新字节的高4位为0,将两个结果相加,则结果相当于原字节交换了高、低4位;
2.取出高4位中的低2位、低4位中的低2位(与0x33即可),左移2位,则取出的两对2位分别变成了相应4位中的高2位;同理取出各4位中的高2位(与0xCC即可),右移2位,则实现了交换每4位中的高2位、低2位;
3.与上述原理相同,交换每2位中的高位和低位(与0x55、与0xAA);
代码如下:
/*******************************************************************************
* 函数名:ReverseBits
* 功 能:字节按位反转
* 参 数:Byte:需要反转的字节
* 返回值:Byte:反转后的字节
* 说 明:无
*******************************************************************************/
uint8_t ReverseBits(uint8_t Byte)
{
Byte = (Byte << 4) + (Byte >> 4);//交换高4位、低4位
Byte = ((Byte & 0x33) << 2) + ((Byte & 0xCC) >> 2);//交换每4位中的高2位、低2位
Byte = ((Byte & 0x55) << 1) + ((Byte & 0xAA) >> 1);//交换每2位中的高位、低位
return Byte;
}
四、试验验证
测试0xAB的反转结果,代码如下:
void main(void)
{
uint8_t original = 0xAB;
uint8_t reversed = 0;
reversed = ReverseBits(original);
printf("original data is:0x%02X;\n",original);
printf("reversed data is:0x%02X;\n",reversed);
}
运行结果:
original data is:0xAB;
reversed data is:0xD5;
五、总结
一个字节可表示的数据只有256种,如果将0x00~0xFF按位反转的值做成表格,使用查表法,则效率更高了。可通过如下代码,获得0x00~0xFF按位反转的值:
uint16_t i;
for (i = 0; i < 0x0100; i++)
{
printf("0x%02X,",ReverseBits(i));
}