?
This document uses PHP Chinese website manual Release
結(jié)構(gòu)是一種由一系列成員組成的類型,其存儲(chǔ)按有序順序進(jìn)行分配(與union相反,這是一種由存儲(chǔ)重疊的成員序列組成的類型)。
union
除了使用的關(guān)鍵字之外,結(jié)構(gòu)的類型說明符與 類型說明符相同:
結(jié)構(gòu)名稱(可選){結(jié)構(gòu)聲明列表} | (1) | |
---|---|---|
結(jié)構(gòu)名稱 | (2) |
1)結(jié)構(gòu)定義:引入新的類型結(jié)構(gòu)名稱并定義它的含義
2)如果在struct
名稱上使用它自己的行;
,則聲明但不定義該結(jié)構(gòu)name
(請(qǐng)參見下面的前向聲明)。在其他上下文中,命名先前聲明的結(jié)構(gòu)。
name | - | 正在定義的結(jié)構(gòu)的名稱 |
---|---|---|
結(jié)構(gòu)聲明列表 | - | 任何數(shù)量的變量聲明,位域聲明和靜態(tài)斷言聲明。不完整類型的成員和函數(shù)類型的成員是不允許的(除了下面描述的靈活數(shù)組成員) |
在一個(gè)結(jié)構(gòu)對(duì)象中,其元素的地址(以及位字段分配單元的地址)按照成員定義的順序增加。指向結(jié)構(gòu)的指針可以轉(zhuǎn)換為指向其第一個(gè)成員的指針(或者,如果該成員是位域,則指向其分配單元)。同樣,可以將指向結(jié)構(gòu)第一個(gè)成員的指針轉(zhuǎn)換為指向封閉結(jié)構(gòu)的指針。在結(jié)構(gòu)的任何兩個(gè)成員之間或者在最后一個(gè)成員之后,可能存在未命名的填充,但不在第一個(gè)成員之前。結(jié)構(gòu)的大小至少與其成員大小的總和一樣大。
如果一個(gè)結(jié)構(gòu)至少定義了一個(gè)指定的成員,那么它允許額外地聲明它的最后一個(gè)成員為不完整的數(shù)組類型。當(dāng)訪問靈活數(shù)組成員的元素時(shí)(在使用運(yùn)算符的表達(dá)式中,或者使用靈活數(shù)組成員的名稱作為右手邊操作數(shù)),那么結(jié)構(gòu)的行為就好像數(shù)組成員具有最長的大小適合為該對(duì)象分配的內(nèi)存。如果沒有分配額外的存儲(chǔ)空間,則它的行為就像一個(gè)具有1個(gè)元素的數(shù)組,除非該行為是未定義的(如果訪問該元素或產(chǎn)生了經(jīng)過該元素的指針)。初始化,sizeof和賦值運(yùn)算符忽略了靈活的數(shù)組成員。具有靈活數(shù)組成員的結(jié)構(gòu)(或其最后一個(gè)成員是具有靈活數(shù)組成員的結(jié)構(gòu)的聯(lián)合結(jié)構(gòu))不能以數(shù)組元素或其他結(jié)構(gòu)成員的形式出現(xiàn)。struct s {int n; double d []; }; // sd是一個(gè)靈活的數(shù)組成員struct s t1 = {0}; // OK,d就好像是double d1,但UB訪問struct s t2 = {1,{4.2}}; //錯(cuò)誤:初始化忽略靈活數(shù)組//如果sizeof(double)== 8 struct s * s1 = malloc(sizeof(struct s)+ 64); //好像d是雙d8 struct s * s2 = malloc(sizeof(struct s)+ 46); //好像d是double d5 s1 = malloc(sizeof(struct s)+ 10); //現(xiàn)在好像d是double d1 s2 = malloc(sizeof(struct s)+ 6); //相同,但UB訪問double * dp =&(s1-> d0); // OK * dp = 42; // OK dp =&(s2-> d0); // OK * dp = 42; //未定義行為* s1 = * s2; //只復(fù)制sn,而不是sd的任何元素//除了在sizeof(struct s)中捕獲的元素外, | (自C99以來) |
---|
類似于聯(lián)合,一個(gè)結(jié)構(gòu)的未命名成員的類型是一個(gè)沒有名字的結(jié)構(gòu)被稱為匿名結(jié)構(gòu)。匿名結(jié)構(gòu)的每個(gè)成員都被認(rèn)為是封閉結(jié)構(gòu)或聯(lián)合的成員。如果封閉的結(jié)構(gòu)或聯(lián)合也是匿名的,則這將遞歸應(yīng)用。struct v {union {//匿名聯(lián)合結(jié)構(gòu){int i,j; }; //匿名結(jié)構(gòu)struct {long k,l; } w; }; int m; } v1; v1.i = 2; //有效v1.k = 3; //無效:內(nèi)部結(jié)構(gòu)不是匿名的v1.wk = 5; // valid與union類似,如果struct沒有任何指定成員(包括通過匿名嵌套結(jié)構(gòu)或聯(lián)合獲得的成員)定義,則程序的行為是未定義的。 | (自C11以來) |
---|
以下表格的聲明。
結(jié)構(gòu)名稱; |
---|
隱藏標(biāo)簽名稱空間中名稱名稱的任何先前聲明的含義,并將名稱聲明為當(dāng)前作用域中的新結(jié)構(gòu)名稱,稍后將對(duì)其進(jìn)行定義。在定義出現(xiàn)之前,此結(jié)構(gòu)名稱的類型不完整。
這允許相互引用的結(jié)構(gòu):
struct y;struct x { struct y *p; /* ... */ };struct y { struct x *q; /* ... */ };
請(qǐng)注意,只需在另一個(gè)聲明中使用結(jié)構(gòu)標(biāo)簽即可引入新的結(jié)構(gòu)名稱,但如果在標(biāo)簽名稱空間中存在以前聲明的具有相同名稱的結(jié)構(gòu),則該標(biāo)簽將引用該名稱。
struct s* p = NULL; // tag naming an unknown struct declares itstruct s { int a; }; // definition for the struct pointed to by pvoid g(void){ struct s; // forward declaration of a new, local struct s // this hides global struct s until the end of this block struct s *p; // pointer to local struct s // without the forward declaration above, // this would point at the file-scope s struct s { char* p; }; // definitions of the local struct s}
struct
.
有關(guān)結(jié)構(gòu)初始化程序的規(guī)則,請(qǐng)參閱結(jié)構(gòu)初始化。
因?yàn)椴煌暾愋偷某蓡T是不允許的,并且結(jié)構(gòu)類型直到定義結(jié)束才會(huì)完成,所以結(jié)構(gòu)體不能擁有自己類型的成員。允許指向它自己的類型的指針,并且通常用于實(shí)現(xiàn)鏈接列表或樹中的節(jié)點(diǎn)。
因?yàn)榻Y(jié)構(gòu)聲明不會(huì)建立范圍,所以struct-declaration-list中的聲明引入的嵌套類型,枚舉和枚舉器在定義了結(jié)構(gòu)的周圍范圍內(nèi)是可見的。
#include <stddef.h>#include <stdio.h> int main(void){ struct car { char *make; char *model; int year; }; // declares the struct type // declares and initializes an object of a previously-declared struct type struct car c = {.year=1923, .make="Nash", .model="48 Sports Touring Car"}; printf("car: %d %s %s\n", c.year, c.make, c.model); // declares a struct type, an object of that type, and a pointer to it struct spaceship { char *make; char *model; char *year; } ship = {"Incom Corporation", "T-65 X-wing starfighter", "128 ABY"}, *pship = &ship; printf("spaceship: %s %s %s\n", ship.year, ship.make, ship.model); // addresses increase in order of definition // padding may be inserted struct A { char a; double b; char c;}; printf("offset of char a = %zu\noffset of double b = %zu\noffset of char c = %zu\n" "sizeof(struct A)=%zu\n", offsetof(struct A, a), offsetof(struct A, b), offsetof(struct A, c), sizeof(struct A)); struct B { char a; char b; double c;}; printf("offset of char a = %zu\noffset of char b = %zu\noffset of double c = %zu\n" "sizeof(struct B)=%zu\n", offsetof(struct B, a), offsetof(struct B, b), offsetof(struct B, c), sizeof(struct B)); // A pointer to a struct can be cast to a pointer to its first member and vice versa char* pmake = (char*)&ship; pship = (struct spaceship *)pmake;}
可能的輸出:
car: 1923 Nash 48 Sports Touring Car spaceship: 128 ABY Incom Corporation T-65 X-wing starfighter offset of char a = 0offset of double b = 8offset of char c = 16sizeof(struct A)=24offset of char a = 0offset of char b = 1offset of double c = 8sizeof(struct B)=16
C11標(biāo)準(zhǔn)(ISO / IEC 9899:2011):
6.7.2.1結(jié)構(gòu)和聯(lián)合說明符(p:112-117)
C99標(biāo)準(zhǔn)(ISO / IEC 9899:1999):
6.7.2.1結(jié)構(gòu)和聯(lián)合說明符(p:101-104)
C89 / C90標(biāo)準(zhǔn)(ISO / IEC 9899:1990):
3.5.2.1結(jié)構(gòu)和聯(lián)合說明符