C語言struct關鍵字詳解—結構體

struct 是個神奇的關鍵字,它將一些相關聯的數據打包成一個總體,方便使用。

在網絡協議、通訊控制、嵌入式系統、驅動開發等地方,咱們常常要傳送的不是簡單的字節流(char 型數組),而是多種數據組合起來的一個總體,其表現形式是一個結構體。

經驗不足的開發人員每每將全部須要傳送的內容依順序保存在char 型數組中,經過指針偏移的方法傳送網絡報文等信息。這樣作編程複雜,易出錯,並且一旦控制方式及通訊協議有所變化,程序就要進行很是細緻的修改,很是容易出錯。這個時候只須要一個結構體就能搞定。平時咱們要求函數的參數儘可能很少於4 個,若是函數的參數多於4 個使用起來很是容易出錯(包括每一個參數的意義和順序都容易弄錯),效率也會下降(與具體CPU 有關,ARM芯片對於超過4 個參數的處理就有講究,具體請參考相關資料)。這個時候,能夠用結構體壓縮參數個數。

1、空結構體多大?

結構體所佔的內存大小是其成員所佔內存之和(關於結構體的內存對齊,請參考預處理那章)。這點很容易理解,可是下面的這種狀況呢?
struct student
{
}stu;

sizeof(stu)的值是多少呢?在Visual C++ 6.0 上測試一下。

很遺憾,不是0,而是1。爲何呢?你想一想,若是咱們把struct student 當作一個模子的話,你能造出一個沒有任何容積的模子嗎?

顯然不行。編譯器也是如此認爲。 編譯器認爲任何一種數據類型都有其大小,用它來定義一個變量可以分配肯定大小的空間。既然如此,編譯器就理所固然的認爲任何一個結構體都是有大小的,哪怕這個結構體爲空。那萬一結構體真的爲空,它的大小爲何值比較合適呢?

假設結構體內只有一個char 型的數據成員,那其大小爲1byte(這裏先不考慮內存對齊的狀況).也就是說非空結構體類型數據最少須要佔一個字節的空間,而空結構體類型數據總不能比最小的非空結構體類型數據所佔的空間大吧。這就麻煩了,空結構體的大小既不能爲0,也不能大於1,怎麼辦?定義爲0.5個byte?可是內存地址的最小單位是1 個byte,0.5 個byte 怎麼處理?解決這個問題的最好辦法就是折中,編譯器理所固然的認爲你構造一個結構體數據類型是用來打包一些數據成員的,而最小的數據成員須要1 個byte,編譯器爲每一個結構體類型數據至少預留1 個byte的空間。因此,空結構體的大小就定位1 個byte。

2、柔性數組

也許你歷來沒有據說過柔性數組(flexible array)這個概念,可是它確實是存在的。

C99 中,結構中的最後一個元素容許是未知大小的數組,這就叫作柔性數組成員,但結構中的柔性數組成員前面必須至少一個其餘成員。柔性數組成員容許結構中包含一個大小可變的數組。sizeof 返回的這種結構大小不包括柔性數組的內存。包含柔性數組成員的結構用malloc ()函數進行內存的動態分配,而且分配的內存應該大於結構的大小,以適應柔性數組的預期大小。

柔性數組到底如何使用呢?看下面例子:
typedef struct st_type
{
   int i;
   int a[0];
}type_a;

有些編譯器會報錯沒法編譯能夠改爲:
typedef struct st_type
{
   int i;
   int a[];
}type_a;

這樣咱們就能夠定義一個可變長的結構體, 用sizeof(type_a) 獲得的只有4 , 就是sizeof(i)=sizeof(int)。那個0 個元素的數組沒有佔用空間,然後咱們能夠進行變長操做了。經過以下表達式給結構體分配內存:
   type_a *p = (type_a*)malloc(sizeof(type_a)+100*sizeof(int));
這樣咱們爲結構體指針p 分配了一塊內存。用p->item[n]就能簡單地訪問可變長元素。

可是這時候咱們再用sizeof(*p)測試結構體的大小,發現仍然爲4。是否是很詭異?咱們不是給這個數組分配了空間麼?

別急,先回憶一下咱們前面講過的「模子」。在定義這個結構體的時候,模子的大小就已經肯定不包含柔性數組的內存大小。柔性數組只是編外人員,不佔結構體的編制。只是說在使用柔性數組時須要把它看成結構體的一個成員,僅此而已。再說白點,柔性數組其實與結構體沒什麼關係,只是「掛羊頭賣狗肉」而已,算不得結構體的正式成員。

須要說明的是:C89 不支持這種東西,C99 把它做爲一種特例加入了標準。可是,C99所支持的是incomplete type,而不是zero array,形同int item[0];這種形式是非法的,C99 支持的形式是形同int item[];只不過有些編譯器把int item[0];做爲非標準擴展來支持,並且在C99 發佈以前已經有了這種非標準擴展了,C99 發佈以後,有些編譯器把二者合而爲一了。

固然,上面既然用malloc 函數分配了內存,確定就須要用free 函數來釋放內存:
   free(p);
通過上面的講解,相信你已經掌握了這個看起來彷佛很神祕的東西。不過實在要是沒掌握也無所謂,這個東西實在不多用。

3、struct 與class 的區別

在C++裏struct 關鍵字與class 關鍵字通常能夠通用,只有一個很小的區別。struct 的成員默認狀況下屬性是public 的,而class 成員倒是private 的。不少人以爲很差記,其實很容易。你平時用結構體時用public 修飾它的成員了嗎?既然struct 關鍵字與class 關鍵字能夠通用,你也不要認爲結構體內不能放函數了。 固然,關於結構體的討論遠沒有結束,在指針與數組那一章,你還會要和它打交道的。
相關文章
相關標籤/搜索