首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C >> C 語言入門

C 語言變長陣列結構體:char data[0] 柔性陣列成員完整解析

     編輯:C 語言入門

前言:結構體記憶體對齊機制

在探討柔性陣列成員前,必須理解結構體的 記憶體對齊 機制,這直接影響 sizeof 結果與柔性陣列的實際位移。

對齊核心規則

  1. 成員對齊:每個成員起始位址必須是其型別大小的整數倍,不足則填充
  2. 整體對齊:結構體總大小必須是所有成員中最大對齊值的整數倍

32/64 位元常見型別對齊值

型別32-bit64-bit Linux
char11
short22
int/float44
double8 (Win) / 4 (Linux)8
指標48

柔性陣列成員

語法與原理

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); // 一次釋放結構體與資料區

經典陷阱:offsetof 與 padding 差異

來源:ChinaUnix 論壇實戰案例

問題場景

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 bytes9 bytes
結果正確多算 3 bytes → 越界讀取 → Segfault

正確做法

  • 額外新增 data_len 欄位明確記錄資料長度
  • 或 使用 sizeof(*cmd) - offsetof(packet, data) 但仍需注意對齊
  • C99 標準建議改用 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 語言實現變長結構體的標準技巧
  • 必須搭配動態記憶體配置,不可用於棧上區域變數
  • 警惕 offsetof 與 sizeof 的對齊差異,嚴重時導致緩衝區溢位
  • 現代 C 專案建議改用 C99 flexible array member 語法 char data[]

圖片資源

結構體定義 成員宣告 結構體結尾 程式碼區塊 表情符號

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved