宣告:本文主要**了文章中關於 「零長度陣列的內容」,在此對原作者表示感謝
首先,我們要知道,0長度的陣列在iso c和c++的規格說明書中是不允許的。這也就是為什麼在vc++2012下編譯你會得到乙個警告:「arning c4200: 使用了非標準擴充套件 : 結構/聯合中的零大小陣列」。
那麼為什麼gcc可以通過而連乙個警告都沒有?那是因為gcc 為了預先支援c99的這種玩法,所以,讓「零長度陣列」這種玩法合法了。
關於gcc對於這個事的文件在這裡:「arrays of length zero」,文件中給了乙個例子(我改了一下,改成可以執行的了):
1 #include 2 #include 34struct
line ;89
intmain()
上面這段**的意思是:我想分配乙個不定長的陣列,於是我有乙個結構體,其中有兩個成員,乙個是length,代表陣列的長度,乙個是contents,**陣列的內容。後面**裡的 this_length(長度是10)代表是我想分配的資料的長度。(這看上去是不是像乙個c++的類?)這種玩法英文叫:flexible array,中文翻譯叫:柔性陣列。
我們來用gdb看一下:
(gdb) p thisline$1 = (struct line *) 0x601010
(gdb) p *thisline
$2 =
(gdb) p thisline->contents
$3 = 0x601014
"aaaaaaaaaa
"
我們可以看到:在輸出*thisline時,我們發現其中的成員變數contents的位址居然和thisline是一樣的(偏移量為0x0??!!)。但是當我們輸出thisline->contents的時候,你又發現contents的位址是被offset了0x4了的,內容也變成了10個『a』。(我覺得這是乙個gdb的bug,vc++的偵錯程式就能很好的顯示)
我們繼續,如果你sizeof(char[0])或是 sizeof(int[0]) 之類的零長度陣列,你會發現sizeof返回了0,這就是說,零長度的陣列是存在於結構體內的,但是不佔結構體的size。你可以簡單的理解為乙個沒有內容的佔位標識,直到我們給結構體分配了記憶體,這個佔位標識才變成了乙個有長度的陣列。
看到這裡,你會說,為什麼要這樣搞啊,把contents宣告成乙個指標,然後為它再分配一下記憶體不行麼?就像下面一樣。
1struct
line ;56
intmain()
這不一樣清楚嗎?而且也沒什麼怪異難懂的東西。是的,這也是普遍的程式設計方式,**是很清晰,也讓人很容易理解。即然這樣,那為什麼要搞乙個零長度的陣列?有毛意義?!
這個事情出來的原因是——我們想給乙個結構體內的資料分配乙個連續的記憶體!這樣做的意義有兩個好處:
第乙個意義是,方便記憶體釋放。如果我們的**是在乙個給別人用的函式中,你在裡面做了二次記憶體分配,並把整個結構體返回給使用者。使用者呼叫free可以釋放結構體,但是使用者並不知道這個結構體內的成員也需要free,所以你不能指望使用者來發現這個事。所以,如果我們把結構體的記憶體以及其成員要的記憶體一次性分配好了,並返回給使用者乙個結構體指標,使用者做一次free就可以把所有的記憶體也給釋放掉。(讀到這裡,你一定會覺得c++的封閉中的析構函式會讓這事容易和乾淨很多)
第二個原因是,這樣有利於訪問速度。連續的記憶體有益於提高訪問速度,也有益於減少記憶體碎片。(其實,我個人覺得也沒多高了,反正你跑不了要用做偏移量的加法來定址)
我們來看看是怎麼個連續的,用gdb的x命令來檢視:(我們知道,用struct line {}中的那個char contents不占用結構體的記憶體,所以,struct line就只有乙個int成員,4個位元組,而我們還要為contents分配10個位元組長度,所以,一共是14個位元組)
(gdb) x /14b thisline0x601010: 1000
0979797
970x601018: 97
9797
9797
97
從上面的記憶體布局我們可以看到,前4個位元組是 int length,後10個位元組就是char contents。
如果用指標的話,會變成這個樣子:
(gdb) x /16b thisline0x601010: 100
0000
00x601018: 32
169600
000(gdb) x /10b this->contents
0x601020: 97
9797
9797
9797
970x601028: 97
97
上面一共輸出了四行記憶體,其中,
從這裡,我們看到,其中的差別——陣列的原地就是內容,而指標的那裡儲存的是內容的位址。
[1]
零長度陣列
零長度陣列 神奇的int reserve 0 include include struct device 構題 device 之後 這種宣告方法可以巧妙的實現c語 言裡的陣列擴充套件 int main a.out p dev reserve 0 100 p dev reserve 24 0 size...
零長度陣列
最近在準備分析linux input子系統,發現核心 裡面有很多小技巧。特此記錄下,如有不足之處,敬請指正。在日常的程式設計中,有時候需要在結構體中存放乙個長度動態的字串,比如說,我們要在結構體中存放乙個名字,但是這個名字的長度是未知的。於是,我們就會採用以下兩種方法來解決這個問題。注 以下的 都是...
零長度陣列
適用於c語言變長陣列 在實際的程式設計中,我們經常需要使用變長陣列,但是c語言並不支援變長的陣列。此時,我們可以使用結構體的方法實現c語言變長陣列。struct mydata 在結構中,data是乙個陣列名 但該陣列沒有元素 該陣列的真實位址緊隨結構體mydata之後,而這個位址就是結構體後面資料的...