C語言的struct hack整理

在C語言中,有一個技巧叫struct hack,主要是要實現動態大小的struct

要紀錄的資訊有名字欄位,可以這樣設計

struct person_info
{
  int age;
  char name[32];
};

但是這邊假設name存的字串最長是31 + 1 bytes (null terminated string),
如果要能動態長度就要改用指標處理,例如

struct person_info
{
  char gender;
  char* name;
};

struct person_info alice;
alice.gender = 'F';
alice.name = malloc(sizeof("alice"));
strcpy(alice.name, "alice");

這個的缺點就是 name的記憶體配置是另外配置,和person_info不在同一處,可能無法利用到cpu cache。

struct hack的作法是讓尾端可以動態大小,此時在struct最後面定義一個place holder

strcut person_info
{
  char gender; //'M', 'F'
  char name[0]; //zero length array
};

//sizeof(struct person_info) => 1

struct person_info* alice = malloc(sizeof(struct person_info) + sizeof("alice"));

malloc 會allocate 一塊空間包含struct member所需的,剩下的空間可以用name來存取

注意這裡name的用途是拿來做place holder,不用另外計算struct之後的起始位置,因為有時候有alignment padding的問題。

alice->gender = 'F';
strcpy(alice->name, "alice");

strcut person_info
{
  char gender; //'M', 'F' (佔據 0 byte位置)
               //第1,2,3 byte位置 padding
  int data[0]; //第4byte開始...
};

//sizeof(struct person_info) => 4
//data的alignment是在 4 byte boundary。

struct hack的作法只能用在最後一個member是不定大小。在C99 可以用flexible array member來描述 char name[];

flexible array member算是incomplete array type,所以不能直接sizeof

§6.2.5 #12 An array type of unknown size is an incomplete type.

§6.5.3.4 The sizeof operator
The sizeof operator shall not be applied to an expression that has function type or an incomplete type.

但是標準給出了一個例外

§6.7.2.1 第16點
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 flexible array member. … the size of the structure shall be equal to the offset of the last element of an otherwise identical structure that replaces the flexible array member with an array of unspecified length

另外需注意的是,因為flexible array member是C99的標準,在那之前一般是用zero length array來做place holder,

zero length array事實上是gcc的extension。標準C不允許zero length array

§6.7.5.2 Array declarators
If the expression is a constant expression, it shall have a value greater than zero. The element type shall not be an incomplete or function type.

上面提到的const expression是指Array [N]的N,要求 > 0

參考:

https://wiki.sei.cmu.edu/confluence/display/c/DCL38-C.+Use+the+correct+syntax+when+declaring+a+flexible+array+member

https://www.geeksforgeeks.org/struct-hack/

This entry was posted in C Language. Bookmark the permalink.

Leave a Reply