問題
對一個字節數據,逐個交換其高低位,例如11010001,經過0-7,1-6,2-5,3-4對應位的交換,變成10001011 。
解決思路
對於該問題,我們最先想到的是對原字節通過移位操作來逐位處理,使用另一個變量來存儲交換後的結果。這種解決方案處理起來思路清晰,編寫代碼應該不難。
下面是該思路對應的代碼:
[cpp]
unsigned char shift_fun1(unsigned char data)
{
unsigned char i;
unsigned char tmp=0x00;
for(i=0;i<8;i++)
{
tmp=((data>>i)&0x01)|tmp;
if(i<7)
tmp=tmp<<1;
}
printf(" after shift fun1 data=%x \n",tmp);
return tmp;
}
上述代碼實現起來不難,而且效率還是比較高的。但是還有比這更簡潔的解決方法,在嵌入式開發中遇到交換字節位的問題時通常使用蝶式交換法和查表法來實現。查表法顧名思義即將一些值存到內存中,需要計算時查表即可,但是也會占用額外的存儲空間。這裡主要再介紹一下蝶式交換法。
所謂的蝶式交換是這樣的:
[cpp]
data=(data<<4)|(data>>4);
data=((data<<2)&0xcc)|((data>>2)&0x33);
data=((data<<1)&0xaa)|((data>>1)&0x55);
我們可以做一下執行演算:
假設原始位序列為 0 1 0 1 1 0 0 1
data=(data<<4)|(data>>4);之後序列為 1 0 0 1 0 1 0 1
data=((data<<2)&0xcc)|((data>>2)&0x33); 之後序列為 0 1 1 0 0 1 0 1
data=((data<<1)&0xaa)|((data>>1)&0x55); 之後序列為 1 0 0 1 1 0 1 0
更抽象的來說 原始位為 1 2 3 4 5 6 7 8
data=(data<<4)|(data>>4); 之後位序為 5 6 7 8 1 2 3 4
data=((data<<2)&0xcc)|((data>>2)&0x33); 之後位序為 7 8 5 6 3 4 1 2
data=((data<<1)&0xaa)|((data>>1)&0x55); 之後位序為 8 7 6 5 4 3 2 1
由此完成了整個位的逆序轉換,下面是具體的實現代碼:
[cpp]
unsigned char shift_fun2(unsigned char data)
{
data=(data<<4)|(data>>4);
data=((data<<2)&0xcc)|((data>>2)&0x33);
data=((data<<1)&0xaa)|((data>>1)&0x55);
printf(" after shift fun2 data=%x \n",data);
return data;
}
總結
交換字節的高低位並不是一個很常見的問題,遇到該問題時,需要經過仔細的分析,加上對C語言位操作的熟練掌握,就能夠很好的解決這一類的問題。