C語言進(jìn)階之結(jié)構(gòu)體、聯(lián)合、枚舉、sizeof
掃描二維碼
隨時(shí)隨地手機(jī)看文章
結(jié)構(gòu)是由若干(可不同類型的)數(shù)據(jù)項(xiàng)組合而成的復(fù)合數(shù)據(jù)對象,這些數(shù)據(jù)項(xiàng)稱為結(jié)構(gòu)的成分或成員。
(1)字段
C語言的結(jié)構(gòu)還提供了一種定義字段的機(jī)制,使人在需要時(shí)能把幾個(gè)結(jié)構(gòu)成員壓縮到一個(gè)基本數(shù)據(jù)類型成員成員里存放,這可以看作是一種數(shù)據(jù)壓縮表示方式。
struct pack{
unsigned a:2;
unsigned b:8;
unsigned c:6;
}pk1,pk2;
結(jié)構(gòu)變量pk1或者pk2的三個(gè)成員將總共占用16位存儲(chǔ),其中a占用2位,b占用8位,c占用6位。
(2)結(jié)構(gòu)體內(nèi)部的成員對齊
在計(jì)算結(jié)構(gòu)體長度(尤其是用sizeof)時(shí),需要注意!根據(jù)不同的編譯器和處理器,結(jié)構(gòu)體內(nèi)部成員有不同的對齊方式,這會(huì)引起結(jié)構(gòu)體長度的不確定性。
#include
struct a{char a1; char a2; char a3;}A;
struct b{short a2; char a1;}B;
void main(void)
{
printf("%d,%d,%d,%d",sizeof(char),sizeof(short),sizeof(A),sizeof(B));
}
在Turbo C 2.0中結(jié)果都是
1,2,3,3
在VC6.0中是
1,2,3,4
字節(jié)對齊的細(xì)節(jié)和編譯器實(shí)現(xiàn)相關(guān),但一般而言,滿足三個(gè)準(zhǔn)則:
1)結(jié)構(gòu)體變量的首地址能夠被其最寬基本類型成員的大小所整除;
2)結(jié)構(gòu)體每個(gè)成員相對于結(jié)構(gòu)首地址的偏移量(offset)都是成員大小的整數(shù)倍,如有需要編譯器會(huì)在成員之間加上填充字節(jié)(internal adding);
3)結(jié)構(gòu)體的總大小為結(jié)構(gòu)體最寬基本類型成員大小的整數(shù)倍,如有需要編譯器會(huì)在最末一個(gè)成員之后加上填充字節(jié)(trailing padding)。
對于上面的準(zhǔn)則,有幾點(diǎn)需要說明:
1)結(jié)構(gòu)體某個(gè)成員相對于結(jié)構(gòu)體首地址的偏移量可以通過宏offsetof()來獲得,這個(gè)宏也在stddef.h中定義,如下:
#define offsetof(s,m) (size_t)&(((s *)0)->m)
2) 基本類型是指前面提到的像char、short、int、float、double這樣的內(nèi)置數(shù)據(jù)類型,這里所說的“數(shù)據(jù)寬度”就是指其sizeof的大小。由于結(jié)構(gòu)體的成員可以是復(fù)合類型,比如另外一個(gè)結(jié)構(gòu)體,所以在尋找最寬基本類型成員時(shí),應(yīng)當(dāng)包括復(fù)合類型成員的子成員,而不是把復(fù)合成員看成是一個(gè)整體。但在確定復(fù)合類型成員的偏移位置時(shí),則是將復(fù)合類型作為整體看待。
2 聯(lián)合體在一個(gè)結(jié)構(gòu)(變量)里,結(jié)構(gòu)的各成員順序排列存儲(chǔ),每個(gè)成員都有自己獨(dú)立的存儲(chǔ)位置。聯(lián)合變量的所有成員共享從同一片存儲(chǔ)區(qū)。因此一個(gè)聯(lián)合變量在每個(gè)時(shí)刻里只能保存它的某一個(gè)成員的值。
(1)聯(lián)合變量的初始化
聯(lián)合變量也在可以定義時(shí)直接進(jìn)行初始化,但這個(gè)初始化只能對第一個(gè)成員做。例如下面的描述定義了一個(gè)聯(lián)合體變量,并進(jìn)行了初始化:
union data
{
char n;
float f;
};
union data u1 = {3};//只有u1.n被初始化
一個(gè)枚舉說明不但引進(jìn)了一組常量名,同時(shí)也為每個(gè)常量確定了一個(gè)整數(shù)值。缺省情況下其第一個(gè)常量自動(dòng)給值0,隨后的常量值順序遞增。
(1)給枚舉常量指定特定值
與給變量指定初始值的形式類似。如果給某個(gè)枚舉量指定了值,跟隨其后的沒有指定值的枚舉常量也將跟著順序遞增取值,直到下一個(gè)有指定值的常量為止。例如寫出下面枚舉說明:
enum color
{
RED = 1,
GREEN,
BLUE,
WHITE = 11,
GREY,
BLACK = 15
};
這時(shí),RED、GREEN、BLUE的值將分別是1、2、3,WHITE、GREY的值將分別是11、12,而BLACK的值是15。
(2)用枚舉常量作為數(shù)組長度
typedef enum {
WHITE,
RED,
BLUE,
YELLOW,
BLACK,
COLOR_NUM
}COLOR;
... ...
float BallSize[COLOR_NUM];
上例中當(dāng)顏色數(shù)量發(fā)生變化時(shí),只需要在枚舉類型定義中假如或刪去顏色。無需修改COLOR_NUM的定義。與大量使用#define相比既簡潔又可靠。如:
typedef enum {
WHITE,
RED,
BLUE,
COLOR_NUM
}COLOR;
4 sizeof的定義和使用
sizeof 是c/c++中的一個(gè)操作符(注意!不是函數(shù)!就像return一樣)。其作用就是返回一個(gè)對象或者類型所占的內(nèi)存字節(jié)數(shù)。
sizeof有三種使用形式,如下:
1> sizeof(var); ???????????????? //sizeof(變量);
2> sizeof(type_name);????????????//sizeof(類型);
3> sizeof var; //sizeof 變量;
所以,
int i;
sizeof(i);????????//ok
sizeof i;????????//ok
sizeof(int);????//ok
sizeof int; ????//error
為求形式統(tǒng)一,不建議采用第3種寫法,忘掉它吧!數(shù)組的sizeof
數(shù)組的sizeof值等于數(shù)組所占用的內(nèi)存字節(jié)說,如:
char* SS = "0123456789";
sizeof(SS); //結(jié)果 4,SS是指向字符串常量的字符指針
sizeof(*SS); ????????//結(jié)果 1,*SS是第一個(gè)字符
char SS[] = "0123456789";
sizeof(SS); //結(jié)果 11,計(jì)算到‘