一、簡述
1.1大端小端區別
- 根據計算機中數據在硬件(內存/寄存器)中存儲順序(存儲方式),可以分為大端、小端。
- 大端:低地址存儲高位數據。
- 小端:低地址存儲低位數據。
舉例:0x123456在內存中的存儲方式
1 - 大端模式: 2 低地址 -----> 高地址 3 0x12 | 0x34 | 0x56 4 5 6 - 小端模式 7 低地址 -----> 高地址 8 0x56 | 0x34 | 0x12
1.2大端小端來源
端模式(Endian)的這個詞出自JonathanSwift書寫的《格列佛游記》。這本書根據將雞蛋敲開的方法不同將所有的人分為兩類,從圓頭開始將雞蛋敲開的人被歸為BigEndian,從尖頭開始將雞蛋敲開的人被歸為LittileEndian。小人國的內戰就源於吃雞蛋時是究竟從大頭(Big-Endian)敲開還是從小頭(Little-Endian)敲開。在計算機業BigEndian和LittleEndian也幾乎引起一場戰爭。在計算機業界,Endian表示數據在存儲器中的存放順序。
- 一開始是由於不同架構的CPU處理多個字節數據的順序不一樣,比如x86的是小段模式,KEIL C51是大端模式。但是后來互聯網流行,TCP/IP協議規定為大端模式,為了跨平台通信,還專門出了網絡字節序和主機字節序之間的轉換接口(ntohs、htons、ntohl、htonl)
- 大小端模式各有優勢:小端模式強制轉換類型時不需要調整字節內容,直接截取低字節即可;大端模式由於符號位為第一個字節,很方便判斷正負。
1.3大端、小端設備
小端設備 | 大端設備 |
Pentuim處理器 | PowerPC處理器 |
x86機 | |
IBM,Motorola(PowerPC),Sun的機器 | |
ARM、Alpha、Motorola(PowerPC),即能工作於大端又能工作於小端,需要具體參考處理器手冊。 |
- 大部分用戶的操作系統(如windows, FreeBsd,Linux)是Little Endian的。少部分是Big Endian,如MAC OS 。Little Endian還是Big Endian與操作系統和芯片類型都有關系。
- Linux系統中,可以在/usr/include/中(包括子目錄)查找字符串BYTE_ORDER(或_BYTE_ORDER,__BYTE_ORDER),確定其值。
- BYTE_ORDER中文稱為字節序。這個值一般在endian.h或machine/endian.h文件中可以找到,有時在feature.h中,不同的操作系統可能有所不同。
二、判斷大端小端
原理:
- C/C++中short占2個字節,char占1個字節。0xFF00存入short變量。
- 取short變量中的一個字節數據存入char變量。
- 判斷char變量地址和short變量地址關系。
- 如果char地址比short地址更大,說明從short變量取的數據是高地址數據。
- 判斷char數據是0x00還是0xFF,從而判斷出當前系統是大端還是小端。
測試大端小端代碼(C++):
1 #include <iostream> 2 3 4 5 using namespace std; 6 7 int main() 8 { 9 10 int intData(0xFFFF0000); 11 short *shortData = (short*)(&intData); 12 13 std::cout << "intData address:\t"; 14 std::cout << &intData << endl; 15 16 std::cout << "shortData address:\t"; 17 std::cout << shortData << endl; 18 19 //獲取當前數據地址前一個地址數據和之后一個數據 20 short *low = shortData - 1; 21 short *high = shortData + 1; 22 23 //如果之前一個數據和之后一個數據相等,則沒有辦法判斷,此時需要重新檢測 24 if (*low == *high) 25 { 26 std::cout << "Please check again!\n"; 27 getchar(); 28 return 0; 29 } 30 31 //臨時short變量和其地址內容比較使用 32 //注意不能直接用0xFFFF和short直接比較,否則有時出錯,會把0xFFFF看作int比較 33 short temp = 0xFFFF; 34 35 //當前地址的內容是高位數據 36 if (*shortData == temp) 37 { 38 temp = 0x0000; 39 //*shortData地址是高位地址 40 if (*low == temp) 41 { 42 std::cout << "otherPartData addr:\t"; 43 std::cout << low << endl; 44 std::cout << "====================" << endl; 45 46 std::cout << "shortData is:\t\t"; 47 std::cout << hex << *shortData << endl; 48 std::cout << "otherPartData is:\t"; 49 std::cout << hex << *low << endl; 50 std::cout << "====================" << endl; 51 52 std::cout << "Little endian!\n"; 53 } 54 //*shortData地址是低位地址 55 if (*high == temp) 56 { 57 std::cout << "otherPartData addr:\t"; 58 std::cout << high << endl; 59 std::cout << "====================" << endl; 60 61 std::cout << "shortData is:\t\t"; 62 std::cout << hex << *shortData << endl; 63 std::cout << "otherPartData is:\t"; 64 std::cout << hex << *high << endl; 65 std::cout << "====================" << endl; 66 67 std::cout << "Big endian!\n"; 68 } 69 } 70 //當前地址存儲低位數據 71 else 72 { 73 temp = 0xFFFF; 74 //*shortData地址是高位地址 75 if (*low == temp) 76 { 77 78 std::cout << "otherPartData addr:\t"; 79 std::cout << low << endl; 80 std::cout << "====================" << endl; 81 82 std::cout << "shortData is:\t\t"; 83 std::cout << hex << *shortData << endl; 84 std::cout << "otherPartData is:\t"; 85 std::cout << hex << *low << endl; 86 std::cout << "====================" << endl; 87 88 std::cout << "Big endian!\n"; 89 } 90 //*shortData地址是低位地址 91 if (*high == temp) 92 { 93 std::cout << "otherPartData addr:\t"; 94 std::cout << high << endl; 95 std::cout << "====================" << endl; 96 97 std::cout << "shortData is:\t\t"; 98 std::cout << hex << *shortData << endl; 99 std::cout << "otherPartData is:\t"; 100 std::cout << hex << *high << endl; 101 std::cout << "====================" << endl; 102 103 std::cout << "Little endian!\n"; 104 } 105 } 106 getchar(); 107 return 0; 108 109 }
Window系統運行結果:
1 intData address: 010FFE70 2 shortData address: 010FFE70 3 otherPartData addr: 010FFE72 4 ==================== 5 shortData is: 0 6 otherPartData is: ffff 7 ==================== 8 Little endian! 9