C語言中除了結構體,還有一種很重要的結構,叫做共用體(Union).
共用體定義
共用體(Union)是C語言中一個特殊的數據類型,可以在相同的內存位置存儲不同的數據類型,可以定義一個或者多個成員變量的共用體,但是在指定時刻,只能有一個成員變量的值是完整的有效值.
union [union tag]
{
member definition;
member definition;
...
member definition;
} [one or more union variables];
共用體內存開闢
對於共用體來講,雖然可以定義多個類型的成員變量,但是系統會根據最大的成員變量進行內存開闢,同時只能有一個成員變量在使用,多個成員變量不能同時使用.這是共用體與結構體非常重要的區別.定義共用體:
union Data
{
int i;
float f;
char str[20];
} data;
查看共用體的內存佔用:
printf( "Memory size occupied by data : %d\n", sizeof(data));
輸出結果:
Memory size occupied by data : 20
由此可見,聯合體的內存分配是使用是根據成員變量中需要存儲空間最大的成員變量來確定的,而不是像結構體那樣,將爲每一次成員變量開闢內存空間.
共用體儲存原則
共用體雖然可以定義多個變量,但是由於多個變量之間需要內存共享,所以有限的存儲空間只能保證在在某一時刻只有一個變量的值是完整的有效值,也就是最近一次存儲的成員變量的值是完整的有效值,其餘的成員變量的值將會被覆蓋.
union Data data;
printf( "Memory size occupied by data : %lu\n", sizeof(data));
data.i = 10;
printf( "data.i : %d\n", data.i);
data.f = 220.5;
printf( "data.f : %f\n", data.f);
strcpy( data.str, "C Programming");
printf( "data.i : %d\n", data.i);
printf( "data.f : %f\n", data.f);
printf( "data.str : %s\n", data.str);
輸出結果:
Memory size occupied by data : 20
data.i : 10
data.f : 220.500000
data.i : 1917853763
data.f : 4122360580327794860452759994368.000000
data.str : C Programming
共用體與結構體聯合使用
由於在結構體中,可以通過通過":"來單獨定義各個成員變量所佔據的bit位數,結合聯合體會根據成員變量中所需內存空間最大的成員變量進行內存開闢,於是就產生了個神奇的用法.例如,紅黃藍三原色
union Color {
unsigned int value;
struct {
unsigned char Red;
unsigned char Green;
unsigned char Blue;
};
};
由於共用體會根據成員變量中所需內存最大的成員變量的大小來開闢內存,所以共用體只需要開闢unsigned int類型所需要的內存大小即可.而unsigned char類型的三個變量會在內存中依次存儲.
union Color pix;
pix.Blue = 0X33;
pix.Green = 0X22;
pix.Red = 0X11;
printf("%X\r\n",pix.value);
輸出結果:
6B332211
可以看出,三個成員變量在內存中依次存儲,相當於使用了一個unsigned int類型的變量存儲了三個unsigned char類型的變量,而且可以方便地存取,如果需要單個原色只需要使用(.)運算符直接訪問屬性,如果需要直接使用三原色,只需要取出value的值抹掉高位的一個字節即可(unsigned int佔用四個字節,但是結構體中的成員變量只使用了三個字節,第四個字節是未操作的數據).或許你會忍不住吐槽,明明直接使用結構體就可以搞定的事情你搞這麼麻煩又啥子意義??
只是因爲結構體中的成員變量在基本類型都有定義,所以顯的這種組合有點多餘.但是如果想要在一個基本數據類型中存儲多種信息,並且這種信息只需要幾個bit就可以完成的話,這種結構就具有重要意義:
union isa_t {
uintptr_t bits;
struct {
uintptr_t nonpointer : 1; \
uintptr_t has_assoc : 1; \
uintptr_t has_cxx_dtor : 1; \
uintptr_t shiftcls : 44; /*MACH_VM_MAX_ADDRESS 0x7fffffe00000*/ \
uintptr_t magic : 6; \
uintptr_t weakly_referenced : 1; \
uintptr_t deallocating : 1; \
uintptr_t has_sidetable_rc : 1; \
uintptr_t extra_rc : 8
};
};
這樣的話只需要,只是用了一個uintptr_t(unsigned long)類型的成員變量,就可以完成9個變量的完美存取,不僅大大節約了內存空間,簡化了存取的流程,加快了存取效率,而且便於理解和閱讀.這種定義方式成爲位域結構.