1. 程式人生 > >為什麼C++中空類和空結構體大小為1?

為什麼C++中空類和空結構體大小為1?

原文連結:http://www.spongeliu.com/260.html

對於結構體和空類大小是1這個問題,首先這是一個C++問題,在C語言下空結構體大小為0(當然這是編譯器相關的)。這裡的空類和空結構體是指類或結構體中沒有任何成員。

在C++下,空類和空結構體的大小是1(編譯器相關),這是為什麼呢?為什麼不是0?

這是因為,C++標準中規定,“no object shall have the same address in memory as any other variable” ,就是任何不同的物件不能擁有相同的記憶體地址。 如果空類大小為0,若我們宣告一個這個類的物件陣列,那麼陣列中的每個物件都擁有了相同的地址,這顯然是違背標準的。

但是,也許你還有一個疑問,為什麼C++標準中會有這麼無聊的規定呢?

當然,這樣規定顯然是有原因的。我們假設C++中有一個型別T,我們宣告一個型別T的陣列,然後再宣告一個T型別的指標指向陣列中間某個元素,則我們將指標減去1,應該得到陣列的另一個索引。如下程式碼:

T array[5];
  
int diff = &array[3] - &array[2];
  
 // diff = 1

上面的程式碼是一種指標運算,將兩個指標相減,編譯器作出如下面式子所示的動作:

diff = ((char *)&array[3] - (char *)&array[2]) / sizeof T;

式子應該不難懂把,很明顯的一點就是這個式子的計算依賴於sizeof T。雖然上面只是一個例子,但是基本上所有的指標運算都依賴於sizeof T。

好,下面我們來看,如果允許不同的物件有相同的地址將會引發什麼樣的問題,看下面的例子:

&array[3] - &array[2] = &array[3] - &array[1]
                      = &array[3] - &array[1]
                      = &array[3] - &array[0]
                      = 0
                      

我們可以看到,在這個例子中,如果每個物件都擁有相同地址,我們將沒有辦法通過指標運算來區分不同的物件。還有一個更嚴重的問題,就是如果 sizeof T是0,就會導致編譯器產生一個除0的操作,引發不可控的錯誤。

基於這個原因,如果允許結構體或者類的大小為0,編譯器就需要實現一些複雜的程式碼來處理這些異常的指標運算。

所以,C++標準規定不同的物件不能擁有相同的地址。那麼怎樣才能保證這個條件被滿足呢?最簡單的方法莫過於不允許任何型別的大小為0。所以編譯器為每個空類或者空結構體都增加了一個虛設的位元組(有的編譯器可能加的更多),這樣這些空類和空結構的大小就不會是0,就可以保證他們的物件擁有彼此獨立的地址。