關鍵字union,又稱為聯合體、共用體,聯合體的聲明和結構體類似,但是它的行為方式又和結構體不同,這里的行為方式主要指的是其在內存中的體現,結構體中的成員每一個占據不同的內存空間,而聯合體中的所有成員共用的是內存中相同的位置。
簡單看下區別:
struct MyStruct
{
double a;
int b;
char c;
};
struct MyStruct value;
union MyUnion
{
double a;
int b;
char c;
};
union MyUnion value;
同樣是定義變量value; 內存空間占用情況如下:
可以看出,結構體變量中3個成員相當于3個人,每個人必須要住一間屋子,優點是空間包容性強,但是內存空間必須全部分配,不管房子住不住人。 聯合體變量3個成員,它們可以共用一間屋子,但是每個屋子同一時間只能容納一個成員,因此不夠包容,成員是互斥的,但是可以大大節省內存空間。
要注意的是,聯合體的長度大小為最大的成員的大小,在本例中即value.a的大小。 并不是單指數據類型,若在MyUnion定義了數組char c[10],則此時該聯合體變量value大小為10個字節。
以上簡單的了解了下union的基本定義,在實際應用中我們一般都使用結構體來定義數據組合而成的結構型變量,而在各數據類型各變量占用空間差不多并且對各變量同時使用要求不高的場合(單從內存使用上)也可以靈活的使用union。
1、變量的初始化
在初始化的時候,只應對一個成員進行初始化即在初始化列表中只有一個初始值。 原因就是聯合體的所有成員共用一個首地址,在默認情況下,會將這個初始值初始化給聯合體變量的第一個成員。
union MyUnion
{
double a;
int b;
char c;
};
//為第一個成員初始化
union MyUnion un1 = {5.0f};
//錯誤初始化,不能為多個成員初始化
union MyUnion un1 = {5.0f, 10};
//對其它位置的成員進行初始化,則可以通過指定初始化方式
union MyUnion un1 = {.b = 10};
//結構體一樣,也可以將一個聯合體變量作為初始值,直接初始化給同類型的另一個聯合體變量
union MyUnion un2 = un1;
2、數據位操作
#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;
}
可以看出,通過訪問和修改聯合體中的定義bitdata成員,可以間接的訪問和修改定義的bytedata的值,這可以用在嵌入式的寄存器位操作上。
3、和struct嵌套使用
比如我們分別定義電視和空調的屬性:
struct tvFeature //電視屬性
{
char *logo; //品牌
int price; //價格
int screensize //屏幕尺寸
int resolution //分辨率
}tvFeature;
struct tvFeature tvfeature;
struct airFeature //空調屬性
{
char *logo; //品牌
int price; //價格
int coldcapacity;//制冷量
int hotcapacity;//制熱量
}airFeature;
struct airFeature airfeature;
可以看出電視和空調有相同的屬性,也有各自特有的屬性。 我們可以使用家用電器的數據結構統一定義。 但是這樣用統一的數據結構定義電視和空調的變量之間耦合會增加很多,對于tvfeature和airfatureta各自來說用不到的屬性也會浪費內存空間。
struct homeappliancesFeature //電器屬性
{
char *logo; //品牌
int price; //價格
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 //空調屬性
{
int coldcapacity;//制冷量
int hotcapacity;//制熱量
}airFeature;
struct homeappliancesFeature //電器屬性
{
char *logo; //品牌
long country; //國家
union
{
struct tvFeature tvST;
struct airFeature airST;
};
};
struct homeappliancesFeature tvfeature;
struct homeappliancesFeature airfature;
如上我們只需一個結構體,就可以解決電視和空調的屬性不同問題; struct tvFeature tvST和struct airFeature airST共用一塊內存空間,定義變量時,可以訪問各自的特有屬性,這樣就解決了內存浪費和變量耦合高的問題。
4、數據復制
例如串口數據發送時,可以直接使用數據復制的方式將數據打包發送,不需要將一個4字節的數據額外進行拆分為4個單字節的數據; 反之讀取數據時,也可以不用將4個單字節的數據重新通過移位拼接為一個4字節數據。
typedef union
{
uint8 data8[4];
uint32 data32;
}dataType;
uint32 sendData = 0x5A5AA5A5;
uint32 receiveData;
dataType commSend;
void main(void)
{
uint8 commData[128];
//數據復制
commData.data32 = sendData;
//發送數據,字節復制,不需要再將commData.data32單獨移位拆分
commData[0]= commSend.data8[0];
commData[1]= commSend.data8[1];
commData[2]= commSend.data8[2];
commData[3]= commSend.data8[3];
//讀取數據時,字節復制,不需要再將已經讀取到的4個單字節數據拼接
receiveData = commData.data32;
}
5、分時發送不同幀格式數據
比如需要在同一段通信數據發送邏輯中,針對不同通信協議幀格式進行發送時,就可以這樣定義數據結構。
typedef struct
{
uint8 head; //幀頭格式相同
union //中間數據格式不一樣
{
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:在使用聯合體時可以注意這兩個點:
1、數據大小端
使用聯合體時需要注意數據大小端問題,這個取決于實際的處理器的存儲方式。
大端存儲就是高字節數據放在低地址。
小端存儲就是高字節數據放在高地址.
如下方例子,可以知道使用的處理器的存儲方式:
#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、指針方式訪問
由于在一個成員長度不同的聯合體里,分配給聯合體的內存大小取決于它的最大成員的大小。 如果內部成員的大小相差太大,當存儲長度較短的成員時,浪費的空間是相當可觀的,在這種情況下,更好的方法是在聯合體中存儲指向不同成員的指針而不是直接存儲成員本身。 所有指針的長度都是相同的,這樣能解決內存空間浪費的問題。
#include
typedef struct
{
unsigned char a;
int b;
}stValue1;
typedef struct
{
int c;
unsigned char d[10];
double e;
}stValue2;
//聯合體成員定義為指針成員
union Un
{
stValue1 *ptrSt1;
stValue2 *ptrSt2;
};
int main()
{
union Un *info;
info->ptrSt1->a = 5;
info->ptrSt2->e = 9.7f;
}
總之在實際使用聯合體union過程中一句話總結:圍繞成員互斥和內存共享這兩個核心點去靈活設計你的數據結構。
-
嵌入式
+關注
關注
5085文章
19138瀏覽量
305689 -
內存
+關注
關注
8文章
3028瀏覽量
74098 -
關鍵字
+關注
關注
0文章
37瀏覽量
6908 -
結構體
+關注
關注
1文章
130瀏覽量
10848 -
union
+關注
關注
0文章
10瀏覽量
4285
發布評論請先 登錄
相關推薦
評論