掃二維碼與項(xiàng)目經(jīng)理溝通
我們?cè)谖⑿派?4小時(shí)期待你的聲音
解答本文疑問/技術(shù)咨詢/運(yùn)營(yíng)咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流
聯(lián)合體舉例如下

成都創(chuàng)新互聯(lián)公司-專業(yè)網(wǎng)站定制、快速模板網(wǎng)站建設(shè)、高性價(jià)比綏陽(yáng)網(wǎng)站開發(fā)、企業(yè)建站全套包干低至880元,成熟完善的模板庫(kù),直接使用。一站式綏陽(yáng)網(wǎng)站制作公司更省心,省錢,快速模板網(wǎng)站建設(shè)找我們,業(yè)務(wù)覆蓋綏陽(yáng)地區(qū)。費(fèi)用合理售后完善,10年實(shí)體公司更值得信賴。
union data{
char n;
char ch;
char f;
};
union data a, b, c;結(jié)構(gòu)體和聯(lián)合體的區(qū)別在于:結(jié)構(gòu)體的各個(gè)成員會(huì)占用不同的內(nèi)存,互相之間沒有影響;而聯(lián)合體的所有成員占用同一段內(nèi)存,修改一個(gè)成員會(huì)影響其余所有成員。
結(jié)構(gòu)體占用的內(nèi)存大于等于所有成員占用的內(nèi)存的總和(存在字節(jié)對(duì)齊問題,這里不深入討論)。
聯(lián)合體占用的內(nèi)存等于最長(zhǎng)的成員占用的內(nèi)存。聯(lián)合體中如果對(duì)新的成員賦值,就會(huì)把原來成員的值覆蓋掉。
//上文的聯(lián)合體定義
char data;
a.n = 0x0A;//雖然只修改了成員變量n,但是ch和f變量都會(huì)被改變
data = a.f;//那么data的值就會(huì)被修改為0x0A
聯(lián)合體在一般中的編程應(yīng)用中還是很少的,在單片機(jī)編程中較多,在之前的文章《枚舉和結(jié)構(gòu)體的結(jié)合》將枚舉和結(jié)構(gòu)體的結(jié)合,下面的例子簡(jiǎn)單說明下聯(lián)合體在結(jié)構(gòu)體中的應(yīng)用(我的日常開發(fā)中聯(lián)合體一般都是和結(jié)構(gòu)體一起使用的)。
在做顯示屏應(yīng)用時(shí)牽扯到一個(gè)概念,顯示屏(全彩)上一個(gè)像素點(diǎn)是由于Red,Green,Blue三種顏色組成,在888模式下,每個(gè)像素點(diǎn)都是由8個(gè)bit組成的,這個(gè)時(shí)候?yàn)榱吮闶且粋€(gè)像素點(diǎn)就需要用到結(jié)構(gòu)體,這也對(duì)應(yīng)前面的文章,結(jié)構(gòu)體就像是打包封裝,把一些有共同特征的變量封裝在內(nèi)部。
typedef struct{
uint8_t Red;
uint8_t Green;
uint8_t Blue;
uint32_t Pix_Value;
}LCD_Pixvalue_S;上面這樣的寫法是十分清晰的,訪問很方便,可以單獨(dú)訪整個(gè)像素,也可以訪問像素的某個(gè)顏色,有個(gè)問題那就是我操作紅色像素,需要重新給Pix_Value成員賦值,如下
LCD_Pixvalue_S LCD_Pixvalue;
LCD_Pixvalue.Red = 0x12;
LCD_Pixvalue.Pix_Value = LCD_Pixvalue.Red<<16 | LCD_Pixvalue.Red<<8 |LCD_Pixvalue.Blue;
需要多一句代碼,并且內(nèi)存占用也大。當(dāng)然,直接用下面寫法,不會(huì)多占用內(nèi)存,但是訪問不方便。
typedef struct{
uint32_t Pix_Value;
}LCD_Pixvalue_S;那么這個(gè)時(shí)候,使用聯(lián)合體和結(jié)構(gòu)體組合起來,就可以既不會(huì)多占內(nèi)存,訪問也很方便。
typedef union{
struct{
uint8_t Red;
uint8_t Green;
uint8_t Blue;
}Pix;
uint32_t Pix_Value;
}LCD_Pixvalue_S;那么就可以如下操作
LCD_Pixvalue_S LCD_Pixvalue;
uint32_t data;
LCD_Pixvalue.Pix_Value = 0x0012FF00;
LCD_Pixvalue.Pix.Red = 0x25;//單獨(dú)修改紅色
data = LCD_Pixvalue.Pix_Value;//data的值就為0x0025FF00
當(dāng)然,結(jié)構(gòu)體的定義你也可以寫到外面,其他地方可以使用,如下
typedef struct{
uint8_t Red;
uint8_t Green;
uint8_t Blue;
}Pix_s;
typedef union{
Pix_s Pix;
uint32_t Pix_Value;
}LCD_Pixvalue_S;那么關(guān)于內(nèi)存占用的問題,上面的定義方法,定義一個(gè)LCD_Pixvalue_S類型的變量占用4個(gè)字節(jié)。示例圖如下
上面舉例LCD應(yīng)用中聯(lián)合體的應(yīng)用,這個(gè)是由于LCD一個(gè)像素由紅綠藍(lán)3色組成,所以用聯(lián)合體很方便。在單片機(jī)項(xiàng)目開發(fā)中,串口協(xié)議解析也可以利用到聯(lián)合體,十分方便。
在私有自定義協(xié)議中,合理定義協(xié)議,利用聯(lián)合體代碼十分方便。下面的例子不講幀頭,幀尾部分,舉例聯(lián)合體在協(xié)議解析中的應(yīng)用,靈活應(yīng)用。
串口協(xié)議舉例如下
|
功能 |
字節(jié)長(zhǎng)度 |
|
命令長(zhǎng)度 |
4 |
|
命令字 |
1 |
|
命令內(nèi)容 |
7 |
|
crc16 |
2 |
那么代碼可以如下編寫
typedef union{
struct{
uint32_t cmdlen;
uint8_t cmd;
uint8_t cmdbuf[7];
uint16_t crc16;
}unit;
uint8_t buffer[14];
}uart_buffer_s;
uart_buffer_s uart_buffer;
int main(void)
{
uint8_t len;
len = 0;
uart_buffer.buffer[len++] = 0x12;
uart_buffer.buffer[len++] = 0x34;
uart_buffer.buffer[len++] = 0x56;
uart_buffer.buffer[len++] = 0x78;
uart_buffer.buffer[len++] = 0xAA;
for(int i=0;i<7;i++)
{
uart_buffer.buffer[len++] = i;
}
uart_buffer.buffer[len++] = 0x11;
uart_buffer.buffer[len++] = 0x22;
while (1);
}運(yùn)行的結(jié)果如下
可以看到,我們只是往uart_buffer.buffer填充數(shù)據(jù),模擬串口接收數(shù)據(jù),接收完畢后,就自動(dòng)解析出來我們自定義的cmdlen,cmd,cmdbuf和crc16。這里需要注意的是16位和32位的數(shù)據(jù)類型是小端模式,關(guān)于小端模式請(qǐng)看之前的文章《C語(yǔ)言在STM32中的內(nèi)存分配》,這個(gè)還是很方便的。
!!!但是!!!需要注意字節(jié)對(duì)齊的問題,比如把上述cmdbuf修改為8個(gè)字節(jié),就會(huì)出問題,如下
crc16就會(huì)出問題,這個(gè)就是字節(jié)對(duì)齊的問題,不懂的同學(xué)自行百度一下,這里不再重點(diǎn)講解。
除了上述自定義協(xié)議解析時(shí)會(huì)用到聯(lián)合體,還可以解決浮點(diǎn)型float的讀取問題,float是占用4個(gè)字節(jié)的,如果將從串口接收的4個(gè)字節(jié)轉(zhuǎn)換成float呢?聯(lián)合體就可以可以解決這個(gè)問題
下面示例代碼,我們知道浮點(diǎn)數(shù)231.5的16進(jìn)制表示為0x43678000。
typedef union{
float data;
uint8_t buffer[4];
}uart_buffer_s;
uart_buffer_s uart_buffer;
int main(void)
{
uint8_t len;
len = 0;
uart_buffer.buffer[len++] = 0x00;
uart_buffer.buffer[len++] = 0x80;
uart_buffer.buffer[len++] = 0x67;
uart_buffer.buffer[len++] = 0x43;
while (1);
}結(jié)果如下
可以看到我們模擬從串口收到4個(gè)字節(jié),使用聯(lián)合體,不用我們額外寫代碼,就可以自動(dòng)轉(zhuǎn)化為float型。當(dāng)然這個(gè)轉(zhuǎn)換也是小端模式的,小端模式詳解請(qǐng)看文章《C語(yǔ)言在STM32中的內(nèi)存分配》。

我們?cè)谖⑿派?4小時(shí)期待你的聲音
解答本文疑問/技術(shù)咨詢/運(yùn)營(yíng)咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流