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