在探討柔性陣列成員前,必須理解結構體的 記憶體對齊 機制,這直接影響 sizeof 結果與柔性陣列的實際位移。
| 型別 | 32-bit | 64-bit Linux |
|---|---|---|
| char | 1 | 1 |
| short | 2 | 2 |
| int/float | 4 | 4 |
| double | 8 (Win) / 4 (Linux) | 8 |
| 指標 | 4 | 8 |
struct MyData {
int nLen;
char data[0]; // C99 標準寫法,GCC 亦支援 data[]
};
data[0] 不佔用結構體大小(sizeof(struct MyData) == sizeof(int))data 位址緊接結構體之後,作為動態資料的起始位置malloc(sizeof(struct MyData) + extra_size) 實現變長資料struct MyData *p = malloc(sizeof(struct MyData) + 10); p->nLen = 10; memcpy(p->data, "123456789", 10); // 透過 p->data 操作 10 bytes 動態資料 free(p); // 一次釋放結構體與資料區
typedef struct {
int head;
int size;
char reply;
char data[0];
} packet;
// 錯誤計算資料長度
#define offsetof(type, element) ((int)&((type *)0)->element)
size_t packet_data_len(packet* cmd) {
return cmd->size - offsetof(packet, data); // 陷阱!
}
| 項目 | sizeof 計算 | offsetof 計算 |
|---|---|---|
| reply 後填充 | 3 bytes (對齊至 4) | 0 bytes (不考慮填充) |
| data 位移 | 12 bytes | 9 bytes |
| 結果 | 正確 | 多算 3 bytes → 越界讀取 → Segfault |
data_len 欄位明確記錄資料長度sizeof(*cmd) - offsetof(packet, data) 但仍需注意對齊
char data[](不指定大小),語意更清晰// 訊息佇列節點
typedef struct MsgNode {
struct MsgNode *next;
uint32_t msg_id;
uint16_t payload_len;
char payload[]; // 柔性陣列
} MsgNode;
MsgNode* create_msg(uint32_t id, const void* data, uint16_t len) {
MsgNode *node = malloc(sizeof(MsgNode) + len);
node->msg_id = id;
node->payload_len = len;
memcpy(node->payload, data, len);
return node;
}
char data[0] / char data[] 是 C 語言實現變長結構體的標準技巧flexible array member 語法 char data[]
