計算機數據存儲有兩種字節優先順序:高位字節優先(稱為大端模式)和低位字節優先(稱為小端模式)。
大端模式,是指數據的高字節保存在內存的低地址中,而數據的低字節保存在內存的高地址中,這樣的存儲模式有點兒類似於把數據當作字符串順序處理:地址由小向大增加,而數據從高位往低位放;這和我們的閱讀習慣一致。
小端模式,是指數據的高字節保存在內存的高地址中,而數據的低字節保存在內存的低地址中,這種存儲模式將地址的高低和數據位權有效地結合起來,高地址部分權值高,低地址部分權值低。
例子:對於內存中存放的數0x12345678來說
如果是采用大端模式存放的,則其真實的數是:0x12345678
如果是采用小端模式存放的,則其真實的數是:0x78563412
如果稱某個系統所采用的字節序為主機字節序,則它可能是小端模式的,也可能是大端模式的。
而端口號和IP地址都是以網絡字節序存儲的,不是主機字節序,網絡字節序都是大端模式。
要把主機字節序和網絡字節序相互對應起來,需要對這兩個字節存儲優先順序進行相互轉化。
這里用到四個函數:htons(),ntohs(),htonl()和ntohl().
這四個地址分別實現網絡字節序和主機字節序的轉化,這里的h代表host,n代表network,s代表short,l代表long。
通常16位的IP端口號用s代表,而IP地址用l來代表。
#include <arpa/inet.h> uint32_t htonl(uint32_t hostlong); uint16_t htons(uint16_t hostshort); uint32_t ntohl(uint32_t netlong); uint16_t ntohs(uint16_t netshort);
htonl 表示 host to network long ,用於將主機 unsigned int 型數據轉換成網絡字節順序;
htons 表示 host to network short ,用於將主機 unsigned short 型數據轉換成網絡字節順序;
ntohl、ntohs 的功能分別與 htonl、htons 相反。

如圖,i為int類型占4個字節,但只有1個字節的值為1,另外3個字節值為0;取出低地址上的值,當其為1時則為小端模式,為0時為大端模式。
//大小端模式的判斷 //方法一:利用聯合體所有成員的起始位置一致, //對聯合體中的int類型賦值,然后判斷聯合體中char類型的值的大小
#include <iostream>
#include <iomanip>
using namespace std;
//signed
typedef signed char int8;
typedef short int16;
typedef int int32;
typedef long long int64;
//unsigned
typedef unsigned char uint8;
typedef unsigned short uint16;
typedef unsigned int uint32;
typedef unsigned long long uint64;
#pragma pack(push)
#pragma pack(1)//單字節對齊
typedef struct{
uint32 ID;
uint32 Num;
uint32 Type;
uint32 lat;
uint32 lng;
uint32 alt;
uint32 speed;
}Waypoint;//Payload_Data
#pragma pack(pop)
void EndianSwap(uint8 *pData, int startIndex, int length);
int main()
{
Waypoint wp,wp_ori;
int len = sizeof(Waypoint);
cout << "size of Waypoint: " << len << endl;
wp.ID = 0x00000011;
wp.Num = 0x00002200;
wp.Type = 0xDD0CB0AA;
wp.lat = 0x00330000;
wp.lng = 0x44000000;
wp.alt = 0xABCD1234;
wp.speed = 0x12345678;
wp_ori = wp;
int i = 0;
uint8* pData = (uint8*)(&wp);
for (i = 0; i < len; i += 4)
{
EndianSwap(pData,i,4);
}
cout << endl;
cout << uppercase << hex << "改變字節序前: 0x" << setfill('0') << setw(8) << wp_ori.ID << endl;
cout << uppercase << hex << "改變字節序后: 0x" <<setfill('0') << setw(8) << wp.ID <<endl;
cout << endl;
cout << uppercase << hex << "改變字節序前: 0x" << setfill('0') << setw(8) << wp_ori.Num << endl;
cout << uppercase << hex << "改變字節序后: 0x" << setfill('0') << setw(8) << wp.Num << endl;
cout << endl;
cout << uppercase << hex << "改變字節序前: 0x" << setfill('0') << setw(8) << wp_ori.Type << endl;
cout << uppercase << hex << "改變字節序后: 0x" << setfill('0') << setw(8) << wp.Type << endl;
cout << endl;
cout << uppercase << hex << "改變字節序前: 0x" << setfill('0') << setw(8) << wp_ori.lat << endl;
cout << uppercase << hex << "改變字節序后: 0x" << setfill('0') << setw(8) << wp.lat << endl;
cout << endl;
cout << uppercase << hex << "改變字節序前: 0x" << setfill('0') << setw(8) << wp_ori.lng << endl;
cout << uppercase << hex << "改變字節序后: 0x" << setfill('0') << setw(8) << wp.lng << endl;
cout << endl;
cout << uppercase << hex << "改變字節序前: 0x" << setfill('0') << setw(8) << wp_ori.alt << endl;
cout << uppercase << hex << "改變字節序后: 0x" << setfill('0') << setw(8) << wp.alt << endl;
cout << endl;
cout << uppercase << hex << "改變字節序前: 0x" << setfill('0') << setw(8) << wp_ori.speed << endl;
cout << uppercase << hex << "改變字節序后: 0x" << setfill('0') << setw(8) << wp.speed << endl;
return 0;
}
void EndianSwap(uint8 *pData, int startIndex, int length)
{
int i,cnt,end,start;
cnt = length / 2;
start = startIndex;
end = startIndex + length - 1;
uint8 tmp;
for (i = 0; i < cnt; i++)
{
tmp = pData[start+i];
pData[start+i] = pData[end-i];
pData[end-i] = tmp;
}
}
運行結果如下:

