簡體   English   中英

結構中成員的順序是否重要?

[英]Does the order of members in a struct matter?

我在C中發現了一種奇特的行為。請考慮以下代碼:

 struct s {
     int a;
 };      

 struct z {
     int a;
     struct s b[];
 };  

 int main(void) {
     return 0;
 }   

它編譯得很好。 然后像這樣改變struct z成員的順序

struct z {
    struct s b[];
    int a; 
};  

突然間我們得到編譯錯誤field has incomplete type 'struct s []'

這是為什么?

struct中字段的順序很重要 - 不允許編譯器對字段重新排序,因此struct的大小可能會因添加一些填充而改變。

但是,在這種情況下,您要定義一個所謂的彈性成員 ,一個可以更改大小的數組。 靈活成員的規則就是這樣

  • 可能永遠不會有多個這樣的會員,
  • 如果存在,柔性構件必須在最后一個struct ,而
  • 除了靈活的struct必須至少有一個成員。

請參閱此問答,了解使用柔性結構構件的小圖。

編譯器無法計算內存struct sb[]; 會消耗。 這意味着如果結構后面有任何字段,編譯器就無法確定這些字段的位置。

過去曾經(在舊版本的C中)(例如) struct sb[]; 不允許作為結構的成員。 這使得高效的內存管理變得煩人。 舉一個簡單的例子,假設你有一個包含“name”字符串的結構(可能只是幾個字符或很多字符)。 您可以使用固定大小的數組,該數組足以容納最大的名稱(浪費空間),或者使用指針並分配2個內存(一個用於結構,一個用於可變長度名稱字符串)。 或者,您可以使用指針並使其指向結構末尾之外的額外空間,最終會出現如下情況:

    length = strlen(my_string);
    foo = malloc(sizeof(MYSTRUCTURE) + length + 1);
    foo->name = (void *)foo + sizeof(MYSTRUCTURE);   // Set pointer to extra bytes past end of structure
    memcpy(foo->name, my_string, length + 1);

這是最有效的選擇; 但它也很丑陋且容易出錯。

為了解決這個問題,編譯器添加了非標准擴展,以允許在結構的末尾使用“未知大小的數組”。 這使程序員更容易一些,並使其更高效(因為不需要額外的指針成員)。 這最終被C標准采用(也許在C99 - 我不記得了)。

成員的順序通常很重要(即某些填充可能插入字段之間),但在您的特定情況下,您使用的是靈活的成員數組,這在C99中是標准化的 - 6.7.2.1.16

作為一種特殊情況,具有多個命名成員的結構的最后一個元素可能具有不完整的數組類型; 這被稱為靈活的陣列成員。 在大多數情況下,將忽略靈活數組成員。 特別地,結構的尺寸好像省略了柔性陣列構件,除了它可以具有比省略意味着更多的拖尾填充。

你的struct sb[]; member用於訪問多個struct s元素的動態堆分配。

你的問題的標題是“ struct中成員的順序是否重要?”。

代碼中的明顯問題與您的struct包含靈活成員的事實有關。

所以這是一個與struct中成員順序的一般問題相關的另一個問題:


以下面兩個結構為例:

struct s1
{
    int a;
    short b;
    char c;
};

struct s2
{
    char c;
    short b;
    int a;
};

大多數編譯器都會添加填充,以便將每個成員對齊到可被其大小整除的地址。

所以struct s2最終可以編譯成:

struct s2
{
    char c;
    char pad1;
    short b;
    short pad2;
    short pad3;
    int a;
};

這最終會導致struct s1struct s2類型實例的大小不同。

在這種情況下,訂單很重要。 struct z包含一個由structs s組成的數組。 但是,此數組沒有與之關聯的大小,因此編譯器不知道如何分配適當的堆棧空間,因為之后還有另一個struct( int a )字段。 它將如何工作的一個例子:

struct s {
  int a;
}

struct z {
  struct s b[10];
  int a;
}

int main(void) {
  return 0;
}

如果你真的需要數組來改變大小,最好是在堆上分配整個結構,並將數組作為指向struct s指針,然后動態地重新分配它以適應不斷變化的數組大小。 查找malloc (3)realloc 3)calloc (3)free (3)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM