網絡協議、游戲消息、數據庫記錄常涉及「固定頭部 + 變長數據」的結構。C99 引入的柔性數組成員(Flexible Array Member)為此提供了標準、高效、類型安全的解決方案。本文對比傳統指針法,詳細演示柔性數組的定義、內存佈局、分配訪問及優勢。
typedef struct {
unsigned len;
char *pData; // 額外 8/4 字節指針開銷
} Msg;
// 使用時:
Msg *m = malloc(sizeof(Msg) + len);
m->pData = (char*)(m + 1); // 手動計算數據起始地址,易錯
memcpy(m->pData, data, len);
(char*)(m+1),維護成本高。m->pData[i]),間接訪問略慢。typedef struct {
unsigned len;
char data[]; // 不定長數組,不佔用結構體大小
} Message;
// 分配:
Message *msg = malloc(sizeof(Message) + len);
// 直接訪問:
msg->len = len;
memcpy(msg->data, str, len);
printf("%u, %s\n", msg->len, msg->data);
free(msg);
| 方案 | 結構體大小 | 數據起始地址 | 分配次數 | 訪問方式 |
|---|---|---|---|---|
| 指針法 | sizeof(len) + sizeof(ptr) | 需手動計算 (char*)(m+1) | 1 次(含數據) | m->pData[i] 間接 |
| 柔性數組 | sizeof(len) (不含 data[]) | 緊隨結構體後 &msg->data | 1 次(含數據) | msg->data[i] 直接 |
sizeof(Message) 不包含 柔性數組空間,僅含固定部分。malloc/calloc/realloc 動態分配,不能定義靜態/自動變量(如 Message msg; 非法)。free(msg),內存塊整體回收,無洩漏風險。malloc(sizeof(Message) + len) 通常已滿足。// array0.h
typedef struct { unsigned len; char *pData; } Msg;
typedef struct { unsigned len; char data[]; } Message;
// main.c
#include <stdio.h> #include <stdlib.h> #include <string.h> #include "array0.h"
int main() {
char str[] = "hello world!";
unsigned len = sizeof(str);
// 指針法
Msg *m = malloc(sizeof(Msg) + len);
m->len = len; m->pData = (char*)(m+1);
memcpy(m+1, str, len); // 或 memcpy(m->pData, str, len)
printf("%u, %s\n", m->len, m->pData); free(m);
// 柔性數組
Message *msg = malloc(sizeof(Message) + len);
msg->len = len;
memcpy(msg->data, str, len);
printf("%u, %s\n", msg->len, msg->data); free(msg);
return 0;
}
struct Pkt { Header hdr; uint8_t payload[]; };struct Entity { ID id; Component comps[]; };柔性數組是 C 語言處理變長數據的「正統」方式,消除了指針開銷與手動偏移計算,代碼更簡潔、安全、高效,現代系統編程必備技能。