/* C語言零長度數組大小和取值問題 */ #include <stdio.h> #include <stdlib.h> #include <string.h> struct str { int type; char s[0];//零長度的數組 }; struct foo { int type; char *s; }; void test() { printf("str size is [%d] \n", sizeof(struct str)); //打印 4 /* 使用GDB查看匯編代碼 對於struct str 結構體中的 char s[0]來說,匯編代碼用了lea指令,lea 0x04(%rax), %rdx 對於struct foo 結構體中的 char*s來說,匯編代碼用了mov指令,mov 0x04(%rax), %rdx lea全稱load effective address,是把地址放進去,而mov則是把地址里的內容放進去。 訪問成員數組名其實得到的是數組的相對地址,而訪問成員指針其實是相對地址里的內容(這和訪問其它非指針或數組的變量是一樣的) 對於數組 char s[10]來說,數組名 s 和 &s 都是一樣的。char s[0] 表示的是地址。char*s 表示的地址的內容 */ printf("foo size is [%d] \n", sizeof(struct foo)); //32位機器上 打印8 //零長度的數組的打印 struct str s1; printf("Arrays of Length Zero print [%p] \n", s1.s); printf("Arrays of Length Zero print [%p] \n", &s1.s); //結果相同 打印的是char s[0] 的地址 struct foo f1; //printf("Arrays of Length Zero print [%x] \n", f1.s); //程序core down 驗證 char*s 訪問成員指針其實是相對地址里的內容 } //驗證char s[]更多的類似於一個占位符 struct str1 { int length; int flags; char s[0];//零長度的數組(Flexible Array) }; void test1() { //零長度數組的占位符功能 //注意 char s[]更多的類似於一個占位符,並非結構體成員,所以計算結構體大小時,並沒有char s[] printf("===size==='[%d]====\n", sizeof(struct str1)); } int main() { test1(); printf("-----ok------\n"); getchar(); return 0; }
/* C語言零長度數組使用 */ #include <stdio.h> #include <stdlib.h> #include <string.h> #define GTS_HDR(s) ((struct str *)((s)-(sizeof(struct str)))) struct str { int length; unsigned char flags; char s[0];//零長度的數組(Flexible Array) }; /* 零長度的數組優勢 第一個優點是,方便內存釋放。如果我們的代碼是在一個給別人用的函數中,你在里面做了二次內存分配,並把整個結構體返回給用戶。
用戶調用free可以釋放結構體,但是用戶並不知道這個結構體內的成員也需要free,所以你不能指望用戶來發現這個事。所以,
如果我們把結構體的內存以及其成員要的內存一次性分配好了,並返回給用戶一個結構體指針,用戶做一次free就可以把所有的內存也給釋放掉。 第二個優點是,這樣有利於訪問速度。連續的內存有益於提高訪問速度,也有益於減少內存碎片。 零長度數組的具體使用可以參考redis中sds結構 */ char * create(void) { int len = 32; struct str *s1 = NULL; s1 = calloc(1, sizeof(struct str) + len); //模仿redis中sds結構 s1->flags = 1; s1->length = len; //注意 char s[0]只是一個占位符,不占用實際內存空間,所以成員變量char s[0]的offset不是s1->s,而是s1+sizeof(struct str) //因此也不應該對外暴露struct str 結構,防止用戶操作struct str 的內存空間 strcpy((char *)s1 + sizeof(struct str), "hello world "); //錯誤示例 打印空 printf("====error show==[%s]=====\n", s1->s); return (char *)s1 + sizeof(struct str); } void test() { char * s = create(); printf("--s is -[%s]---\n", s); } int main() { test(); printf("-----ok------\n"); getchar(); return 0; }
零長度數組只有GUN/GCC支持 別的廠家可能不支持,此時需要用 char data[1]來代替