我有以下代碼:
#include <stdio.h>
#include <stdint.h>
typedef struct E_s {
uint32_t a;
uint32_t b;
uint32_t c;
} E_t;
typedef struct S_s {
uint32_t data_sz;
char data[];
} S_t;
typedef struct F_s {
E_t E;
S_t S;
char data[16];
//} __attribute__((packed)) full_msg_t;
} F_t;
int main(int argc, char* argv[])
{
F_t out;
printf("sizeof(out.data) = %lu\n", sizeof(out.data));
printf("sizeof(out.E) = %lu\n", sizeof(E_t));
printf("sizeof(out.S) = %lu\n", sizeof(S_t));
printf("sizeof(out) = %lu\n", sizeof(F_t));
return EXIT_SUCCESS;
}
當我運行代碼時,我看到以下輸出:
sizeof(out.data) = 16
sizeof(out.E) = 12
sizeof(out.S) = 4
sizeof(out) = 32
問題:為什么大小是S_t4(第三行輸出)?我期待它是 8 ( uint32_t char[])。為什么大小是char[]不包括尺寸?
此外,out.data和都out.S.data指向同一個記憶體位置,這導致我深入研究并找到上述觀察結果。這里的任何線索也將非常有幫助。我沒想到這兩個變數會重疊。
uj5u.com熱心網友回復:
該標準規定在計算大小時忽略具有靈活陣列成員 (FAM)的結構的可變部分:
作為一種特殊情況,具有多個命名成員的結構的最后一個元素可能具有不完整的陣列型別;這稱為靈活陣列成員。在大多數情況下,靈活陣列成員被忽略。特別是,結構的大小就像省略了柔性陣列成員一樣,只是它可能具有比省略所暗示的更多的尾隨填充。然而,當一個
.(或->) 運算子的左運算元是(指向)具有靈活陣列成員的結構,右運算元命名該成員,它的行為就好像該成員被替換為最長的陣列(具有相同的元素型別),不會使結構大于被訪問的物件;陣列的偏移量應保持靈活陣列成員的偏移量,即使這與替換陣列的偏移量不同。如果這個陣列沒有元素,它的行為就好像它有一個元素,但如果嘗試訪問該元素或生成一個越過它的指標,則行為是不確定的。
強調添加
請注意,struct F_s(aka F_t) 不應被接受;這違反了§6.7.2.1 ?3中的約束:
結構或聯合不應包含不完整或函式型別的成員(因此,結構不應包含自身的實體,但可能包含指向自身實體的指標),但結構的最后一個成員具有超過一個命名成員可能有不完整的陣列型別;這樣的結構(以及任何可能遞回地包含此類結構的成員的聯合)不應是結構的成員或陣列的元素。
編譯器應該拒絕那個(或至少發出診斷),因為違反約束需要診斷。即使編譯器沒有直接拒絕它,您也不能實際使用嵌入式的 FAM,S_t因為 的data成員F_t不會移動 - 結構元素的偏移量在編譯時是固定的。事實上,它會使用data元素 of F_t,但這不是定義的行為。
uj5u.com熱心網友回復:
在這個結構中:
typedef struct S_s {
uint32_t data_sz;
char data[];
} S_t;
該data成員是一個靈活的陣列成員。這樣的成員不會影響結構的大小,因為它的大小沒有指定。這在C 標準的第 6.7.2.1p18 節中有詳細說明:
作為一種特殊情況,具有多個命名成員的結構的最后一個元素可能具有不完整的陣列型別;這稱為靈活陣列成員。在大多數情況下,靈活陣列成員被忽略。特別是,結構的大小就像省略了柔性陣列成員一樣,只是它可能具有比省略所暗示的更多的尾隨填充。
所以大小S_t不包括data成員,這就是為什么sizeof(S_t)是4。
只有在動態分配結構的記憶體時才能使用這樣的成員。例如:
S_t *s = malloc(sizeof(S_t) 10);
這允許您訪問從s->data[0]到s->data[9]
這也意味著您不能將具有靈活陣列成員的結構放入另一個結構或陣列中,因為無法確切知道靈活陣列成員的結束位置。
這在第 6.7.2.1p3 節中有詳細說明:
結構或聯合不應包含不完整或函式型別的成員(因此,結構不應包含自身的實體,但可能包含指向自身實體的指標),但結構的最后一個成員具有超過一個命名成員可能有不完整的陣列型別;這種結構(以及任何可能遞回地包含這種結構的成員的聯合)不應是結構的成員或陣列的元素
uj5u.com熱心網友回復:
char data[];是一個靈活的陣列成員,并且明確保證不計算其大小。因為它主要應該用作,陣列的大小在malloc(sizeof(St_t) n)哪里。ndata
至于S_t S;在另一個結構內部,那是無效的 C,因為包含靈活陣列成員的結構必須放在末尾和最外面的結構中,而您沒有這樣做。因此,您的代碼不能在標準 C 中編譯,并且不可能做出假設out.S.data并且out.data在某種程度上是相同的記憶體,因為所有這些都超出了 C 語言的范圍。我認為 GNU C 可能以非標準擴展的形式提供確定性行為,但我不知道有任何此類保證。
uj5u.com熱心網友回復:
因為結構體 S_t 中的 char[] 被稱為靈活陣列,這是 C 編程語言的 C99 標準中引入的一個特性。
這可能有用的靈活陣列成員結構-c
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/516682.html
標籤:C海合会
