C99 標準引入「柔性陣列成員」:結構體最後一個成員可宣告為未指定大小的陣列(type name[])。前提:結構體至少有一個其他成員。sizeof 不包含柔性陣列大小。配合 malloc 動態分配「結構體大小 + 柔性陣列預期大小」的記憶體,實現變長結構體。
不完全型別缺乏足夠資訊描述完整物件(如長度)。常見:前向宣告 struct test;、未知長度陣列 extern int a[];。需補全才能實例化,僅能定義指標/參考。透過初始化補全:int a[] = {10, 20};。
結構體成員在編譯期確定相對偏移量(含對齊填充)。例如 64 位系統:
struct test { int i; short c; char *p; };
// 偏移:i=0, c=4, p=8 (非 6,因對齊)
存取成員實為 base_address + offset,與實例位址無關。
早期做法:結構體含指標指向動態字串,字串與結構體分離,操作不便。改進:分配 sizeof(struct) + strlen(str) + 1,字串緊接結構體後,透過 (char*)(p+1) 存取,但語法醜陋。GCC 擴展允許零長度陣列 char c[0];,C99 標準化為 char c[];(不完全型別),不佔空間且提供語法糖 p->c 直接存取。
// C99 標準形式
struct s_test {
int a;
double b;
char c[]; // 柔性陣列,必須是最後一個成員
};
// 分配與使用
struct s_test *p = malloc(sizeof(struct s_test) + 100);
p->a = 1; p->b = 2.0;
strcpy(p->c, "hello world"); // 直接像固定陣列一樣使用
// GCC 零長度陣列寫法(非標準)
struct s_test2 { int a; double b; char c[0]; };
#include <stdlib.h> #include <string.h>
struct line {
int length;
char contents[0]; // C99 應為 char contents[];
};
int main() {
int this_length = 10;
struct line *thisline = malloc(sizeof(struct line) + this_length);
thisline->length = this_length;
memset(thisline->contents, 'a', this_length);
return 0;
}
意圖:動態分配不定長資料,length 記錄長度,contents 承載內容。
C4200: nonstandard extension used: zero-sized array in struct/union,需用 C99 寫法 char c[];。char,可為任意型別 float[] 等。static/extern無定義、不可直接宣告變數(僅能指標),因大小未知。memcpy 複製結構體時不會複製柔性陣列內容,需手動處理。