字串在記憶體中按字元順序儲存,CPU 讀取順序一致,無位元組序問題。但 short、int、long 等多位元組型別,不同架構儲存順序不同:
例:int a = 0x01020304
大端記憶體:01 02 03 04
小端記憶體:04 03 02 01
若雙端皆為 x86,因雙重反轉(寫入反序、讀取反序)結果看似正確;但一旦對端為大端架構(如某些網路設備、PowerPC),資料將被錯誤解讀。跨平台網路通訊必須統一為網路位元組序(大端)。
#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong); // host to network long
uint16_t htons(uint16_t hostshort); // host to network short
uint32_t ntohl(uint32_t netlong); // network to host long
uint16_t ntohs(uint16_t netshort); // network to host short
僅支援 2/4 位元組,8 位元組需自行實作。
int is_big_endian(void) {
int test = 0x12345678;
char *p = (char*)&test;
return (*p == 0x12);
}
// 整數轉位元組陣列(大端序)
#define rhton16(h, n) do { (n)[0]=((h)>>8)&0xFF; (n)[1]=(h)&0xFF; } while(0)
#define rhton32(h, n) do { (n)[0]=((h)>>24)&0xFF; (n)[1]=((h)>>16)&0xFF; \
(n)[2]=((h)>>8)&0xFF; (n)[3]=(h)&0xFF; } while(0)
#define rhton64(h, n) do { (n)[0]=((h)>>56)&0xFF; (n)[1]=((h)>>48)&0xFF; \
(n)[2]=((h)>>40)&0xFF; (n)[3]=((h)>>32)&0xFF; \
(n)[4]=((h)>>24)&0xFF; (n)[5]=((h)>>16)&0xFF; \
(n)[6]=((h)>>8)&0xFF; (n)[7]=(h)&0xFF; } while(0)
// 位元組陣列轉整數(大端序)
#define rntoh16(n) (((n)[0]<<8)|(n)[1])
#define rntoh32(n) (((n)[0]<<24)|((n)[1]<<16)|((n)[2]<<8)|(n)[3])
#define rntoh64(n) ( ((uint64_t)(n)[0]<<56) | ((uint64_t)(n)[1]<<48) | \
((uint64_t)(n)[2]<<40) | ((uint64_t)(n)[3]<<32) | \
((uint64_t)(n)[4]<<24) | ((uint64_t)(n)[5]<<16) | \
((uint64_t)(n)[6]<<8) | (uint64_t)(n)[7] )
htonl/htons 或自訂巨集轉為網路序ntohl/ntohs 或自訂巨集轉為主機序掌握位元組序轉換是編寫健壯跨平台網路程式的基礎功夫。