位元組是記憶體寻址的最小單位 (8 bits),可表示 0-255 (無符號) 或 -128~127 (有符號)。當數據超出單字節範圍,需用多字節存儲,由此產生高位字節 (High Byte / Most Significant Byte, MSB)與低位字節 (Low Byte / Least Significant Byte, LSB)的概念。
值: 256 (十進制) = 0x0100 (十六進制) = 00000001 00000000 (二進制)
內存中的兩種存儲順序 (大小端序):
┌──────────────┬──────────────┐
│ 地址 N (低) │ 地址 N+1 (高) │
├──────────────┼──────────────┤
│ 低位字節 │ 高位字節 │ ← 小端序 : 低位字節存低地址 (x86, ARM Cortex-M, RISC-V 常見)
│ 0x00 (LSB) │ 0x01 (MSB) │
└──────────────┴──────────────┘
┌──────────────┬──────────────┐
│ 地址 N (低) │ 地址 N+1 (高) │
├──────────────┼──────────────┤
│ 高位字節 │ 低位字節 │ ← 大端序 : 高位字節存低地址 (網路序、PowerPC、SPARC、部分 ARM)
│ 0x01 (MSB) │ 0x00 (LSB) │
└──────────────┴──────────────┘
#include
#include
void extract_bytes_value(uint16_t val, uint8_t *msb, uint8_t *lsb) {
*msb = (uint8_t)(val >> 8); // 邏輯右移 8 位,取高位字節 (值層面)
*lsb = (uint8_t)(val & 0xFF); // 掩碼取低位字節 (值層面)
}
int main() {
uint16_t v = 0x1234;
uint8_t hi, lo;
extract_bytes_value(v, &hi, &lo);
printf("Value 0x%04X -> MSB: 0x%02X, LSB: 0x%02X\n", v, hi, lo);
// 輸出: Value 0x1234 -> MSB: 0x12, LSB: 0x34 (無論大小端機器)
return 0;
}
/* 透過指針訪問內存字節順序 (教學演示,實際網路/儲存請用 htons/ntohs 或手動移位) */
void inspect_memory_layout(uint16_t val) {
uint8_t *bytes = (uint8_t *)&val; // 違反嚴格別名規則,僅作演示
printf("Address: %p -> Byte 0: 0x%02X, Byte 1: 0x%02X\n", (void*)&val, bytes[0], bytes[1]);
// 小端機器輸出: Byte 0: 0x34 (LSB), Byte 1: 0x12 (MSB)
// 大端機器輸出: Byte 0: 0x12 (MSB), Byte 1: 0x34 (LSB)
}
| 場景 | 正確做法 | 錯誤做法 |
|---|---|---|
| 網路協議/檔案格式序列化 (大端/網路序) | 手動移位寫入緩衝區:`buf[0] = val >> 8; buf[1] = val & 0xFF;` 或用 `htons()`/`htonl()` (POSIX) | 直接 `write(fd, &val, 2)` 或 `memcpy(buf, &val, 2)` — 依賴主機序,跨平台失敗 |
| 位運算/標誌位提取/設備寄存器操作 | 用值層面移位掩碼:`(reg >> 8) & 0xFF`,配合 ` | 假設內存佈局,用聯合體/指針強制類型轉換 — UB 風險 |
| 跨平台數據交換 (JSON/Protobuf/MessagePack) | 用成熟庫,或手動轉為大端字節序列 | 直接傳輸二進制結構體內存映射 |
| 校驗和計算 (CRC/Checksum) | 按協議規定的字節序 (通常大端) 逐字節送入演算法 | 直接按主機序內存字節順序計算 |
#include // Linux/macOS/BSD
// #include // Windows (需鏈接 ws2_32.lib)
uint16_t host16 = 0x1234;
uint32_t host32 = 0x12345678;
uint16_t net16 = htons(host16); // Host TO Network Short (16位)
uint32_t net32 = htonl(host32); // Host TO Network Long (32位)
uint16_t host16_back = ntohs(net16); // Network TO Host Short
uint32_t host32_back = ntohl(net32); // Network TO Host Long
理解「值的位模式」與「內存佈局」的分離,是編寫可移植、健壯、高效 C 代碼的關鍵里程碑。