關(guān)鍵字union,又稱為聯(lián)合體、共用體,聯(lián)合體的聲明和結(jié)構(gòu)體類似,但是它的行為方式又和結(jié)構(gòu)體不同,這里的行為方式主要指的是其在內(nèi)存中的體現(xiàn),結(jié)構(gòu)體中的成員每一個(gè)占據(jù)不同的內(nèi)存空間,而聯(lián)合體中的所有成員共用的是內(nèi)存中相同的位置。
簡(jiǎn)單看下區(qū)別:
struct MyStruct
{
double a;
int b;
char c;
};
struct MyStruct value;
union MyUnion
{
double a;
int b;
char c;
};
union MyUnion value;
同樣是定義變量value; 內(nèi)存空間占用情況如下:
可以看出,結(jié)構(gòu)體變量中3個(gè)成員相當(dāng)于3個(gè)人,每個(gè)人必須要住一間屋子,優(yōu)點(diǎn)是空間包容性強(qiáng),但是內(nèi)存空間必須全部分配,不管房子住不住人。 聯(lián)合體變量3個(gè)成員,它們可以共用一間屋子,但是每個(gè)屋子同一時(shí)間只能容納一個(gè)成員,因此不夠包容,成員是互斥的,但是可以大大節(jié)省內(nèi)存空間。
要注意的是,聯(lián)合體的長(zhǎng)度大小為最大的成員的大小,在本例中即value.a的大小。 并不是單指數(shù)據(jù)類型,若在MyUnion定義了數(shù)組char c[10],則此時(shí)該聯(lián)合體變量value大小為10個(gè)字節(jié)。
以上簡(jiǎn)單的了解了下union的基本定義,在實(shí)際應(yīng)用中我們一般都使用結(jié)構(gòu)體來定義數(shù)據(jù)組合而成的結(jié)構(gòu)型變量,而在各數(shù)據(jù)類型各變量占用空間差不多并且對(duì)各變量同時(shí)使用要求不高的場(chǎng)合(單從內(nèi)存使用上)也可以靈活的使用union。
1、變量的初始化
在初始化的時(shí)候,只應(yīng)對(duì)一個(gè)成員進(jìn)行初始化即在初始化列表中只有一個(gè)初始值。 原因就是聯(lián)合體的所有成員共用一個(gè)首地址,在默認(rèn)情況下,會(huì)將這個(gè)初始值初始化給聯(lián)合體變量的第一個(gè)成員。
union MyUnion
{
double a;
int b;
char c;
};
//為第一個(gè)成員初始化
union MyUnion un1 = {5.0f};
//錯(cuò)誤初始化,不能為多個(gè)成員初始化
union MyUnion un1 = {5.0f, 10};
//對(duì)其它位置的成員進(jìn)行初始化,則可以通過指定初始化方式
union MyUnion un1 = {.b = 10};
//結(jié)構(gòu)體一樣,也可以將一個(gè)聯(lián)合體變量作為初始值,直接初始化給同類型的另一個(gè)聯(lián)合體變量
union MyUnion un2 = un1;
2、數(shù)據(jù)位操作
#include
typedef struct
{
unsigned char bit0:1;
unsigned char bit1:1;
unsigned char bit2:1;
unsigned char bit3:1;
unsigned char bit4:1;
unsigned char bit5:1;
unsigned char bit6:1;
unsigned char bit7:1;
}bitValue;
typedef union
{
unsigned char bytedata;
bitValue bitdata;
}regValue;
int main()
{
regValue data;
data.bytedata= 0x5A;
printf("%d",data.bitdata.bit5); //讀取第6位
data.bitdata.bit7 = 1; //修改第8位
return 0;
}
可以看出,通過訪問和修改聯(lián)合體中的定義bitdata成員,可以間接的訪問和修改定義的bytedata的值,這可以用在嵌入式的寄存器位操作上。
3、和struct嵌套使用
比如我們分別定義電視和空調(diào)的屬性:
struct tvFeature //電視屬性
{
char *logo; //品牌
int price; //價(jià)格
int screensize //屏幕尺寸
int resolution //分辨率
}tvFeature;
struct tvFeature tvfeature;
struct airFeature //空調(diào)屬性
{
char *logo; //品牌
int price; //價(jià)格
int coldcapacity;//制冷量
int hotcapacity;//制熱量
}airFeature;
struct airFeature airfeature;
可以看出電視和空調(diào)有相同的屬性,也有各自特有的屬性。 我們可以使用家用電器的數(shù)據(jù)結(jié)構(gòu)統(tǒng)一定義。 但是這樣用統(tǒng)一的數(shù)據(jù)結(jié)構(gòu)定義電視和空調(diào)的變量之間耦合會(huì)增加很多,對(duì)于tvfeature和airfatureta各自來說用不到的屬性也會(huì)浪費(fèi)內(nèi)存空間。
struct homeappliancesFeature //電器屬性
{
char *logo; //品牌
int price; //價(jià)格
int screensize //屏幕尺寸
int resolution //分辨率
int coldcapacity;//制冷量
int hotcapacity;//制熱量
}homeappliancesFeature;
struct homeappliancesFeature tvfeature;
struct homeappliancesFeature airfature;
因此可以用union來解決問題
struct tvFeature //電視屬性
{
int screensize //屏幕尺寸
int resolution //分辨率
}tvFeature;
struct airFeature //空調(diào)屬性
{
int coldcapacity;//制冷量
int hotcapacity;//制熱量
}airFeature;
struct homeappliancesFeature //電器屬性
{
char *logo; //品牌
long country; //國(guó)家
union
{
struct tvFeature tvST;
struct airFeature airST;
};
};
struct homeappliancesFeature tvfeature;
struct homeappliancesFeature airfature;
如上我們只需一個(gè)結(jié)構(gòu)體,就可以解決電視和空調(diào)的屬性不同問題; struct tvFeature tvST和struct airFeature airST共用一塊內(nèi)存空間,定義變量時(shí),可以訪問各自的特有屬性,這樣就解決了內(nèi)存浪費(fèi)和變量耦合高的問題。
4、數(shù)據(jù)復(fù)制
例如串口數(shù)據(jù)發(fā)送時(shí),可以直接使用數(shù)據(jù)復(fù)制的方式將數(shù)據(jù)打包發(fā)送,不需要將一個(gè)4字節(jié)的數(shù)據(jù)額外進(jìn)行拆分為4個(gè)單字節(jié)的數(shù)據(jù); 反之讀取數(shù)據(jù)時(shí),也可以不用將4個(gè)單字節(jié)的數(shù)據(jù)重新通過移位拼接為一個(gè)4字節(jié)數(shù)據(jù)。
typedef union
{
uint8 data8[4];
uint32 data32;
}dataType;
uint32 sendData = 0x5A5AA5A5;
uint32 receiveData;
dataType commSend;
void main(void)
{
uint8 commData[128];
//數(shù)據(jù)復(fù)制
commData.data32 = sendData;
//發(fā)送數(shù)據(jù),字節(jié)復(fù)制,不需要再將commData.data32單獨(dú)移位拆分
commData[0]= commSend.data8[0];
commData[1]= commSend.data8[1];
commData[2]= commSend.data8[2];
commData[3]= commSend.data8[3];
//讀取數(shù)據(jù)時(shí),字節(jié)復(fù)制,不需要再將已經(jīng)讀取到的4個(gè)單字節(jié)數(shù)據(jù)拼接
receiveData = commData.data32;
}
5、分時(shí)發(fā)送不同幀格式數(shù)據(jù)
比如需要在同一段通信數(shù)據(jù)發(fā)送邏輯中,針對(duì)不同通信協(xié)議幀格式進(jìn)行發(fā)送時(shí),就可以這樣定義數(shù)據(jù)結(jié)構(gòu)。
typedef struct
{
uint8 head; //幀頭格式相同
union //中間數(shù)據(jù)格式不一樣
{
struct //payloadType1
{
uint8 cmd;
uint8 type;
uint8 data[5];
uint8 check;
}msgType1;
struct //payloadType2
{
uint16 cmd;
uint8 data[8];
uint16 check;
}msgType2;
uint8 data[10]; //payloadType3
} payloadType;
uint8 end; //幀尾格式相同
}frameType;
By the way:在使用聯(lián)合體時(shí)可以注意這兩個(gè)點(diǎn):
1、數(shù)據(jù)大小端
使用聯(lián)合體時(shí)需要注意數(shù)據(jù)大小端問題,這個(gè)取決于實(shí)際的處理器的存儲(chǔ)方式。
大端存儲(chǔ)就是高字節(jié)數(shù)據(jù)放在低地址。
小端存儲(chǔ)就是高字節(jié)數(shù)據(jù)放在高地址.
如下方例子,可以知道使用的處理器的存儲(chǔ)方式:
#include
union Un
{
int i;
char c;
};
union Un un;
int main()
{
un.i = 0x11223344;
if (un.c == 0x11)
{
printf("大端\\n");
}
else if (un.c == 0x44)
{
printf("小端\\n");
}
}
2、指針方式訪問
由于在一個(gè)成員長(zhǎng)度不同的聯(lián)合體里,分配給聯(lián)合體的內(nèi)存大小取決于它的最大成員的大小。 如果內(nèi)部成員的大小相差太大,當(dāng)存儲(chǔ)長(zhǎng)度較短的成員時(shí),浪費(fèi)的空間是相當(dāng)可觀的,在這種情況下,更好的方法是在聯(lián)合體中存儲(chǔ)指向不同成員的指針而不是直接存儲(chǔ)成員本身。 所有指針的長(zhǎng)度都是相同的,這樣能解決內(nèi)存空間浪費(fèi)的問題。
#include
typedef struct
{
unsigned char a;
int b;
}stValue1;
typedef struct
{
int c;
unsigned char d[10];
double e;
}stValue2;
//聯(lián)合體成員定義為指針成員
union Un
{
stValue1 *ptrSt1;
stValue2 *ptrSt2;
};
int main()
{
union Un *info;
info->ptrSt1->a = 5;
info->ptrSt2->e = 9.7f;
}
總之在實(shí)際使用聯(lián)合體union過程中一句話總結(jié):圍繞成員互斥和內(nèi)存共享這兩個(gè)核心點(diǎn)去靈活設(shè)計(jì)你的數(shù)據(jù)結(jié)構(gòu)。
-
嵌入式
+關(guān)注
關(guān)注
5083文章
19131瀏覽量
305544 -
內(nèi)存
+關(guān)注
關(guān)注
8文章
3028瀏覽量
74082 -
關(guān)鍵字
+關(guān)注
關(guān)注
0文章
37瀏覽量
6907 -
結(jié)構(gòu)體
+關(guān)注
關(guān)注
1文章
130瀏覽量
10848 -
union
+關(guān)注
關(guān)注
0文章
10瀏覽量
4285
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論