變長結構體

在一些 C 語言編寫的代碼中,有時可以看到如下定義的結構:

typedef struct user_def
{
    
char *
 name;
    
int
 length;
    
char bytes[0
];
} user_def_t
;

這個 bytes 是什麼意思?我們知道 0 == sizeof(bytes),那麼 bytes 僅僅是爲了定義結構的尾地址嗎?

不是的。這裏的 bytes 是作爲擴展數組用的。請看如下代碼:

int alloc_user_def_t(user_def_t * p, int length)
{
    p 
= (user_def_t)malloc(sizeof(user_def_t) +
 length);
    
if (NULL ==
 p)
    {
        
return -1
;
    }

    p
->name =
 NULL;
    p
->length =
 length;
    memset(p
->bytes, 0
, length);
    
return 0
;
}

是不是很酷?同樣,也可以把 name 域的值附在結構後面:

int alloc_user_def_t(user_def_t * p, char * name, int length)
{
    p = (user_def_t)malloc(sizeof(user_def_t) + strlen(name) + length + 1);
    if (NULL == p)
    {
        return -1;
    }
    p->name = p + sizeof(user_def_t) + length;
    memcpy(p->name, name, strlen(name) + 1);   /* 別忘了'/0' */
    p->length = length;
    memset(p->bytes, 0, length);
    return 0;
}

總結:在某一結構末尾如定義類似 char bytes[0] 的零長數組,表示該結構不定長,可通過數組的方式進行擴展。結構中必包含一個長度信息。結構本身類似於一個信息頭。同時,此結構只能通過堆方式分配內存。

========================

1.零長度數組不是所有的c標準都支持,gnu c支持,ansi c不支持,c++不支持。

 

2.可以把結構體中定義了零長度數組的地方 視爲結構體的結尾,在它之後最好不要再定義任何字段。因爲零長度數組用來動態的添加數據,一旦添加數據後,零長度數組字段之後定義的字段如果之前賦了值,那麼這個值就會被改掉。(結構體的裏面的數據在內存中按順序存儲的。)

 

3.如何擴展:

可以直接使用數組方式添加信息:

p->bytes[0] = 'a';

p->bytes[1] = 'b';

也可以通過memcpy,strcpy等函數拷貝方式來添加。

 

4.等價寫法:

typedef struct user_def{

    char* name;

    int      length;

    char   bytes[];

}user_def_t;

把char bytes[0] 寫成 char bytes[]也可以,但是這樣寫的話在slickedit裏面調試時,查看結構體的成員時是看不到bytes[]這個成員的,寫成bytes[0]的話就可以。

 

5.注意的問題:

因爲結構體是可以擴展的,所以在給結構體分配內存時必須預先分配足夠的內存,保證後面擴展時不會超過預先分配的內存的大小。比如

01 struct arr{
02     int a;
03     int buff[0];
04 };
05 
06 int main (int argc, char *argv[])
07 {
08     struct arr *ptr;
09     ptr = (struct arr*)malloc(sizeof(struct arr));
10     int* q=(int*)malloc(sizeof(int));
11     int* k=(int*)malloc(sizeof(int));
12 
13     printf("%x %x %x /r/n",ptr,q,k);
14     *q = 1;
15     ptr->buff[0] = 2;
16     ptr->buff[1] = 2;
17     ptr->buff[2] = 2;
18     ptr->buff[3] = 2;
19     printf("%d/r/n",*q);
20 }

 

 

ptr指向結構體,q和k指向的int都是在堆裏面分配的(ptr,q,k本身是在棧中分配的),分配的空間是16個字節(malloc好像默認是最小分16字節,如果大於16字節則按實際的分,在Slickedit和gcc下是這樣,至於malloc的具體內存分配方法暫時沒研究) 。
printf("%x %x %x /r/n",ptr,q,k);的結果是6b0208 6b0218 6b0228,可以看出分了16個字節的空間。
當執行到ptr->buff[2] = 2;時,struct的最後四個字節的內容被置成了2. 接下來ptr->buff[3] = 2就把原來q指向的空間的內容置成了2,所以最後printf("%d/r/n",*q)的結果就是2了。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章