標籤:

怎麼讓我寫出個零位元組的類了?

今天因為工作關係接觸到零長數組,又想到以前關於空類大小的說明,寫了個測試程序,如下:

#include &
#include &

struct zerostruct {
uint32_t a;
char b[0];
};

struct emptyfuncstrcut {
void print() { }
};

struct emptystrcut {
char a[0];
void print() { }
};

int main(int argc, char **argv) {
printf("uint32_t: %d, zerostruct: %d
", sizeof(uint32_t), sizeof(zerostruct));
printf("emptyfuncstruct: %d
", sizeof(emptyfuncstrcut));
printf("emptystruct: %d
", sizeof(emptystrcut));
return 0;
}

輸出為:

uint32_t: 4, zerostruct: 4
emptyfuncstruct: 1
emptystruct: 0

輸出第一因為是因為零長數組不佔用空間

輸出第二則是因為空類大小為零,而編譯器為保證每個類對象都有自己的地址,就分配了1個位元組

奇怪的是第三行為什麼是零???從第一行和第二行得出推論的話應該是1啊

知乎第一問。。。

stackoverflow上已經搜過,沒找到


char a[0];

這東西是個 C-Hack,是個已經過時的東西,目的是為了在 C99 標準前,實現變長數組。[1]

放到現在的標準里,本身就已經不合法,其表現行為是不可知的。(感謝 @Sunchy321 指正)

即便是改為合法的 Flexible array member,根據 C 標準(6.7.2.1 (18) in n1570)[2]:

As a special case, the last element of a structure with more than one named member may have an incomplete array type; this is called a ?exible array member. In most situations, the ?exible array member is ignored. In particular, the size of the structure is as if the ?exible array member were omitted except that it may have more trailing padding than the omission would imply.

所以你的第三個 struct 在 C 語言里嚴格說來並非合法的,可能有 UB。這種情況下,對其進行 sizeof 也就毫無意義了。[3]

至於 C++ 里,根本沒有變長數組這個概念,這樣的 hack 也就無法保證其行為了。

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

  1. c++ - Array of zero length

  2. http://www.compsci.hunter.cuny.edu/~sweiss/resources/c11standard.pdf

  3. c++ - Zero size struct


C++要求任何一個對象佔用空間至少1位元組,都是要能取地址的,試想想佔用0位元組的對象,地址在哪裡,兩三個對象佔用一個地址?你怎麼證明這兩三個對象是不同的對象?


要明白最後一個struct為什麼是0,就要明白0長數組是是怎麼使用的, 如下:

struct emptystrcut {
char a[0];
void print() { }
};

int len = 10;
struct emptystrcut *e = (struct emptystrcut *)
malloc (sizeof (struct emptystrcut) + 10);

如代碼所示,零長數組過去用於實現可變長數組,也就是說他的最終的大小可能是不為0的(也就是說並不一定違反地址規則),所以編譯器也就沒有必要非讓他sizeof為1了。

當然,你也可以構造違反規則的例子(來自ref):

struct baz {
int dummy[0];
};

cout &<&< sizeof(baz) &<&< endl; baz* arr; arr = new baz[5]; cout &<&< arr[0] &<&< endl; cout &<&< arr[1] &<&< endl; return 0;

當然,這個跟編譯器實現有很大關係,可能不同的編譯器版本都會給你不同的結果。所以這是很危險的。

Ref:

Why size of an empty array is 0 but size of an empty class is not 0?


不是很理解為什麼要用零長數組?


推薦閱讀:

各位知友都喜歡用什麼IDE?
把當前各種編程語言的優秀特性集中到一起,設計一種最好的語言,是否可行?
如何用C++從API開始,寫一款Windows上的視頻播放器?
C++重載運算符如何確定運算符位置?
看了很多技術書,為啥仍然寫不出項目?

TAG:編程 | C |