看到老師寫的一個結構體很好奇,結構體的最後是一個長度為0的數組,當時感覺老師是不是寫錯了,這樣寫意義何在呢?都沒有分配空間,貌似沒有存在的意義。
後來網上查了一下,其實這是在很多高級的東東裡面都用到的東西,linux kernel, MFC, openoffice, 估計更多的地方都用到了。
先說說我的理解:
struct example{
__u16 tag_type;
__u16 tag_len;
char tag_data[0];
} __attribute ((packed));
1. 存在的意義:當結構體的長度變長時,例如裡面有一個字符串時,為了方便管理內存。
這個結構體不要用struct example a的方式定義, 而應用struct example *a; a = (struct example *)malloc(sizeof(struct example) + extrasize);的形式。extrasize是想額外申請的空間,就是字符串的長度。
2. 如何使用裡面的數據?
前面的數據項不用說了,後面的tag_data直接就是我們申請的額外的地址的開始地址。所以,很好用
3. 如何釋放申請的地址空間?
直接free(a)就好。有些人可能認為後面的空間沒有釋放,其實不然。因為malloc申請的空間系統是需要進行管理的,你申請了多少,當你釋放的時候,就釋放多少。並不是根據你的數據類型來的,否則你說 char *p; p = malloc(20); 然後free(p);系統該釋放多少空間呢。 至於系統如何管理的,貌似是通過一個鏈表進行的,記不清了。
4. 附1
為了解決這個疑惑,後來看了幾篇文章,感謝他們。
後來就是人提到過有些編譯器不支持0長數組,那怎麼辦呢?很簡單,將數組長度定為1即可,這樣僅僅浪費一個字節的空間(字節對齊的話另當別論)。這樣做還有另外一個好處就是不用記錄這個字符串的長度, 因為本來就存了一個字節的空間,可用這一個字節的空間來標識這個字符串是否為空。
5.附2
有人可能會問,為什麼最後一個數據項不設置成一個指針呢?char tag_data[0]; 和char *tag_data;有什麼區別呢?
第一個問題:最好不要設置成指針,因為這樣的話,你得為tag_data指針重新申請空間,申請的空間還不連續;其次,釋放的時候很麻煩,必須先釋放內部的指針,但是這個往往是人最容易忽略而造成內存呢洩露的原因。
第二個問題:這個問題貌似問的很傻,因為這是兩種不同類型的數據,占據的地址大小都不同。其實不然,這個問題設計到指針和數組的區別問題。
指針和數組很多人都把他們之間畫成等號了,這是個錯誤,希望各位不要犯。他們倆只有在作為函數參數的時候才是真正的一摸一樣,都是指針變量,其他情況都不一樣。最大的區別:數組是直接尋址的,指針是間接尋址的。array[0]中, array 是一個常量,等於&(a[0]); 而指針變量是一個變量。像array = a就不允許賦值(常量怎麼可能作為賦值運算符的左操作數呢?),a = array就是允許的。
6.最後
這個東西用在內存池的管理中用得很多。內存池,這個東西,說起來很嚇唬人,其實就是那麼回事。一個程序或者動態庫維護的一個全局的數組而已,無它。比如說一個c/s架構的服務器,客戶端調用一個預先編好的動態庫中的函數,一般來說不會沒發一個請求網絡就幫你投遞過去,那樣數據太小了。一般都是在動態庫中維護一個數組,把請求往裡面填,填到滿的時候發送出去;或者用戶強行要求發送出去。
這個就跟標准i/o庫很像了,其實裡面也是一段緩存,通過這個緩存使得內存和外存的數據交換不是那麼頻繁,提高了效率。用戶也可以使用fflush()函數強行寫到外存。原理都是類似的。