[Linux Kernel慢慢學]Flexible Array Member

Posted by John on 2020-02-28
Words 475 and Reading Time 1 Minutes
Viewed Times

在C中,有一種struct是在最後一個variable加上一個不指定長度的陣列,用法如下:

1
2
3
4
5
6
7
struct student 
{
int stud_id;
int name_len;
int struct_size;
char stud_name[];
};

沒有大小的陣列稱之flexible array member,在規格書中他是一個incomplete type,所以會被sizeof忽略,也就是說當宣告一個struct的變數的時候,他的大小不會被考慮進去。所以這樣子的話就可以根據需求產生不同長度的空間,比方說最後一個stud_name每個名字長度不同,那就可以根據string length去malloc變數後在指派給stud_name。

1
struct student *s = malloc( sizeof(*s) + sizeof(char [strlen(stud_name)])  );

更多的用法可以參閱Flexible Array Members in a structure in C

此外,Flexible array member也可以用Zero-length array來實現,也就是

1
2
3
4
5
6
7
struct student 
{
int stud_id;
int name_len;
int struct_size;
char stud_name[0];
};

不過zero-length array在C90以前是不被允許的,當時是gcc extension。而在C99後flexible array出來了,由於是C standard,所以使用起來比較不用顧慮相容性的問題,所以建議用後者的寫法。

不過這樣跟原本的寫法(在struct中宣告一個char*指標,然後把指標指到需要的位置上)有什麼差?

  • 由於flexible array member是跟struct一起被malloc的,所以記憶體區段會是連續的,在struct常被存取的時候可以增加cache hit的次數(由於Spatial locality,也就是位置相近的比較常被存取的特性,例如迴圈。而如果用pointer to char array的寫法,記憶體空間並不會是連續的。

不過這種用法有一些要注意的地方:

  • 由於產生的記憶體空間是連續的,所以可能會非法存取到其他變數的記憶體空間。如果compiler又不會檢查那就可能會沒有注意到而產生問題。

Reference


>