大端和小端的判断及转换
當(dāng)前的存儲器,多以byte為訪問的最小單元,當(dāng)一個邏輯上的地址必須分割為物理上的若干單元時就存在了先放誰后放誰的問題,于是端(endian)的問題應(yīng)運(yùn)而生了,對于不同的存儲方法,就有大端(big-endian)和小端(little- endian)兩個描述。
字節(jié)排序按分為大端和小端,概念如下
大端(big endian):低地址存放高有效字節(jié)
小端(little endian):低字節(jié)存放地有效字節(jié)
現(xiàn)在主流的CPU,intel系列的是采用的little endian的格式存放數(shù)據(jù),而motorola系列的CPU采用的是big endian,ARM則同時支持 big和little,網(wǎng)絡(luò)編程中,TCP/IP統(tǒng)一采用大端方式傳送數(shù)據(jù),所以有時我們也會把大端方式稱之為網(wǎng)絡(luò)字節(jié)序。
特別需要注意的是,C/C++語言編寫的程序里數(shù)據(jù)存儲順序是跟編譯平臺所在的CPU相關(guān)的,而 JAVA編寫的程序則唯一采用big endian方式來存儲數(shù)據(jù)。這里我就只討論C/C++語言的情況。
1.大端和小端的方式及判斷
舉個例子說明,我的機(jī)子是32位windows的系統(tǒng),處理器是AMD的。對于一個int型數(shù)0x12345678,為方便說明,這里采用16進(jìn)制表示。這個數(shù)在不同字節(jié)順序存儲的CPU中儲存順序如下:
0x12345678?? 16進(jìn)制,兩個數(shù)就是一字節(jié)
高有效字節(jié)——>低有效字節(jié): 12 34 56 78
????????? 低地址位???? 高低址位
大端:??12? 34??????? 56?? 78
小端:?78? 56??????? 34?? 12
下面驗(yàn)證下本機(jī)CPU屬于哪種字節(jié)存儲順序。代碼如下:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | #include <iostream> ? using?namespace?std; ? typedef?unsigned int?UINT; typedef?unsigned char?UCHAR; ? int?main() { ????UINT?i=0x12345678; ????cout<<hex<<i<<endl; ????UCHAR?*p = (UCHAR*)&i;????????? //將i的地址傳給數(shù)組指針p,實(shí)際上p指向的地址是i在內(nèi)存中存儲的第一個字節(jié),大端就是0x12,小端就是0x78 ????if((*p==0x78)&(*(p+1)==0x56))??????? ????????cout<<"小端"<<endl; ????else?if((*p==0x12)&(*(p+1)==0x34)) ????????cout<<"大端"<<endl; ????else ????????cout<<"這是神馬字節(jié)順序呢?"; ????return?0; } |
調(diào)試顯示時小端,我用的機(jī)子字節(jié)存儲為小端方式。
2.大端和小端的字節(jié)轉(zhuǎn)換
當(dāng)兩臺采用不同字節(jié)序的主機(jī)通信時,在發(fā)送數(shù)據(jù)之前都必須經(jīng)過字節(jié)序的轉(zhuǎn)換成為網(wǎng)絡(luò)字節(jié)序(即大端方式)后再進(jìn)行傳輸。此外用C/C++在小端方式的機(jī)器上編寫的程序與java程序互通時也要進(jìn)行大端和小端的轉(zhuǎn)換。
這里所謂轉(zhuǎn)換就是改變字節(jié)的排序,使交互時數(shù)據(jù)保持一致。舉一個例子,還是16進(jìn)制表示的數(shù)0x12345678,在小端機(jī)器上排序?yàn)?x78563412,當(dāng)內(nèi)存中這樣的數(shù)傳輸時,在大端方式下就是0x78563412這個值,與原值不同,要想與原值相同,在傳輸前,在大端方式下就該是0x12345678,這時原數(shù)在內(nèi)存中為0x12345678,即將原數(shù)據(jù)0x12345678在內(nèi)存存儲序列為0x12345678,也就是要轉(zhuǎn)換成大端方式。
要傳輸值:12 34 56 78
不轉(zhuǎn)換時,小端:78 56 34 12
轉(zhuǎn)換為大端:12 34 56 78
根據(jù)上面的大端和小端字節(jié)排序,可以方便的用移位運(yùn)算完成轉(zhuǎn)換功能。從小端轉(zhuǎn)到大端代碼如下:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | #include <iostream> ? using?namespace?std; ? typedef?unsigned int?UINT; typedef?unsigned char?UCHAR; ? int?main() { ????UINT?i=0x12345678; ????cout<<hex<<i<<endl; ????UCHAR?*p = (UCHAR*)&i; ????UINT?num,num1,num2,num3,num4; ????num1=(UINT)(*p)<<24; ????num2=((UINT)*(p+1))<<16; ????num3=((UINT)*(p+2))<<8; ????num4=((UINT)*(p+3)); ????num=num1+num2+num3+num4; ? ????cout<<"num1:"<<hex<<num1<<endl;???? //看num1的16進(jìn)制表示,下同 ????cout<<"num2:"<<hex<<num2<<endl; ????cout<<"num3:"<<hex<<num3<<endl; ????cout<<"num4:"<<hex<<num4<<endl; ????cout<<"num:"<<hex<<num<<endl; ? ????unsigned char?*q = (unsigned char*)# ????if((*q==0x78)&(*(q+1)==0x56))????????? ????????cout<<"小端"<<endl; ????else?if((*q==0x12)&(*(q+1)==0x34)) ????????cout<<"大端"<<endl; ????else ????????cout<<"這是神馬字節(jié)順序呢?"; ????return?0; } |
至于說(UINT)(*p)為什么要移24位,其實(shí)是很好理解的,將0x00000012變成0x12000000,不就是向左移24位嗎。
當(dāng)然,向上面這樣寫時為了方便理解,可以更簡單的寫一個函數(shù)用于完成上面的轉(zhuǎn)換功能,函數(shù)如下:
| 1 2 3 4 5 | UINT?EndianConvertLToB(UINT?InputNum) { ????UCHAR?*p = (UCHAR*)&InputNum; ????return(((UINT)*p<<24)+((UINT)*(p+1)<<16)+ ???????????????((UINT)*(p+2)<<8)+(UINT)*(p+3)); } |
同樣的原理適用于大端轉(zhuǎn)小端,但是大端轉(zhuǎn)小端時移位有差別,函數(shù)如下:
| 1 2 3 4 5 | UINT?EndianConvertBToL(UINT?InputNum) { ????UCHAR?*p = (UCHAR*)&InputNum; ????return(((UINT)*p)+((UINT)*(p+1)<<8)+ ???????????????((UINT)*(p+2)<<16)+(UINT)*(p+3)<<24); } |
分類:?C/C++
標(biāo)簽:?大端和小端,?轉(zhuǎn)換,?判斷
總結(jié)
以上是生活随笔為你收集整理的大端和小端的判断及转换的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Hex与float之间相互转换
- 下一篇: 【经典算法大全】