位元組序定義多位元組資料在記憶體中的儲存順序。理解大小端對網路程式設計、檔案格式解析、跨平台資料交換至關重要。
| 模式 | 儲存規則 | 別名 | 典型架構 |
|---|---|---|---|
| 大端序 | 高位元組存低地址 | Network Byte Order | PowerPC, SPARC, 網路協議 |
| 小端序 | 低位元組存低地址 | Host Byte Order (Intel x86) | x86, x64, ARM (預設) |
大端序 (Big-Endian) 小端序 (Little-Endian)
地址 0x1000: 0x12 地址 0x1000: 0x78
地址 0x1001: 0x34 地址 0x1001: 0x56
地址 0x1002: 0x56 地址 0x1002: 0x34
地址 0x1003: 0x78 地址 0x1003: 0x12
int check_endian_ptr() {
int a = 1; // 0x00000001
char *p = (char*)&a; // 指向最低地址
return (*p == 1) ? 0 : 1; // 0=小端, 1=大端
}
原理:int 佔 4 位元組,char* 只取最低位址的 1 位元組。小端序低位在低址,故 *p == 1。
int check_endian_union() {
union {
int i;
char c;
} u;
u.i = 1;
return (u.c == 1) ? 0 : 1;
}
聯合體成員共用記憶體,sizeof(union) = max(sizeof(int), sizeof(char)) = 4。賦值 u.i = 1 後,u.c 讀取最低位址位元組。
#include <stdio.h>
int check_endian() {
union { int i; char c; } u = { .i = 1 };
return u.c == 1 ? 0 : 1; // 0: Little, 1: Big
}
int main() {
printf("當前系統: %s-endian\n", check_endian() ? "Big" : "Little");
return 0;
}
TCP/IP 協議規定網路傳輸使用大端序。主機序與網路序轉換函數:
| 函數 | 含義 | 用途 |
|---|---|---|
htons() | Host TO Network Short (16-bit) | 連接埠號 |
htonl() | Host TO Network Long (32-bit) | IPv4 位址 |
ntohs() | Network TO Host Short | 接收連接埠 |
ntohl() | Network TO Host Long | 接收 IP 位址 |
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(8080); // 必須轉換!
addr.sin_addr.s_addr = htonl(INADDR_ANY); // 或 inet_pton 轉換後再 htonl
血淚教訓:假設主機序即網路序會導致跨平台通訊失敗。某專案因未轉換連接埠,在小端機器上正常,部署到大端嵌入式設備即失效。
#pragma pack(push, 1)
struct Packet {
uint16_t len; // 需 htons
uint32_t seq; // 需 htonl
char data[100];
};
#pragma pack(pop)
// 發送前
Packet pkt;
pkt.len = htons(actual_len);
pkt.seq = htonl(seq_num);
send(sock, &pkt, sizeof(pkt), 0);
注意:#pragma pack(1) 禁用對齊填充,確保記憶體佈局與線上格式一致。接收端對應 ntohs/ntohl 還原。