0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

關(guān)鍵字union的基本定義和使用

CHANBAEK ? 來源:明解嵌入式 ? 作者:Sharemaker001 ? 2023-04-15 11:18 ? 次閱讀

關(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)存中相同的位置。

簡單看下區(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)合體的長度大小為最大的成員的大小,在本例中即value.a的大小。 并不是單指數(shù)據(jù)類型,若在MyUnion定義了數(shù)組char c[10],則此時(shí)該聯(lián)合體變量value大小為10個(gè)字節(jié)。

以上簡單的了解了下union的基本定義,在實(shí)際應(yīng)用中我們一般都使用結(jié)構(gòu)體來定義數(shù)據(jù)組合而成的結(jié)構(gòu)型變量,而在各數(shù)據(jù)類型各變量占用空間差不多并且對各變量同時(shí)使用要求不高的場合(單從內(nèi)存使用上)也可以靈活的使用union。

1、變量的初始化

在初始化的時(shí)候,只應(yīng)對一個(gè)成員進(jìn)行初始化即在初始化列表中只有一個(gè)初始值。 原因就是聯(lián)合體的所有成員共用一個(gè)首地址,在默認(rèn)情況下,會將這個(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};
//對其它位置的成員進(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)的變量之間耦合會增加很多,對于tvfeature和airfatureta各自來說用不到的屬性也會浪費(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; //國家
   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ā)送邏輯中,針對不同通信協(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í)際的處理器的存儲方式。

大端存儲就是高字節(jié)數(shù)據(jù)放在低地址。

小端存儲就是高字節(jié)數(shù)據(jù)放在高地址.

如下方例子,可以知道使用的處理器的存儲方式:

#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è)成員長度不同的聯(lián)合體里,分配給聯(lián)合體的內(nèi)存大小取決于它的最大成員的大小。 如果內(nèi)部成員的大小相差太大,當(dāng)存儲長度較短的成員時(shí),浪費(fèi)的空間是相當(dāng)可觀的,在這種情況下,更好的方法是在聯(lián)合體中存儲指向不同成員的指針而不是直接存儲成員本身。 所有指針的長度都是相同的,這樣能解決內(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)。

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • 嵌入式
    +關(guān)注

    關(guān)注

    5046

    文章

    18817

    瀏覽量

    298550
  • 內(nèi)存
    +關(guān)注

    關(guān)注

    8

    文章

    2903

    瀏覽量

    73537
  • 關(guān)鍵字
    +關(guān)注

    關(guān)注

    0

    文章

    37

    瀏覽量

    6882
  • 結(jié)構(gòu)體
    +關(guān)注

    關(guān)注

    1

    文章

    127

    瀏覽量

    10800
  • union
    +關(guān)注

    關(guān)注

    0

    文章

    10

    瀏覽量

    4228
收藏 人收藏

    評論

    相關(guān)推薦

    在NVM和本地\"內(nèi)存中定義數(shù)組(靜態(tài) /global /local)的\"關(guān)鍵字是什么?

    在 NVM 和本地\"內(nèi)存中定義數(shù)組(靜態(tài) /global /local)的\"關(guān)鍵字是什么? 還有與 32 位對齊的關(guān)鍵字怎么樣。
    發(fā)表于 01-25 07:52

    DSP編程技巧之17---非?!?b class='flag-5'>關(guān)鍵”的關(guān)鍵字

    的設(shè)計(jì)產(chǎn)生預(yù)期的結(jié)果。C28x的編譯器支 持所有的標(biāo)準(zhǔn)C89的關(guān)鍵字,包括const、volatile和register,標(biāo)準(zhǔn)的C99關(guān)鍵字,包括inline和restrict,以及支持 TI自定義的擴(kuò)展
    發(fā)表于 08-20 11:38

    static 關(guān)鍵字

    static 關(guān)鍵字 淺析
    發(fā)表于 01-16 16:55

    volatile關(guān)鍵字應(yīng)用場景及示例

    volatile關(guān)鍵字1.應(yīng)用場景2.示例1.應(yīng)用場景volatile關(guān)鍵字分析,往往應(yīng)用在三種場合1)多線程編程共享全局變量的時(shí)候,該全局變量要加上volatile進(jìn)行修飾,讓編譯器不要優(yōu)化該變量
    發(fā)表于 08-24 07:21

    關(guān)鍵字static的作用是什么

    嵌入式面經(jīng)1.關(guān)鍵字static的作用是什么2.關(guān)鍵字const是什么含意?3.const和宏定義的區(qū)別4.關(guān)鍵字volatile有什么含意 并給出三個(gè)不同的例子。5.引用和指針有什么
    發(fā)表于 11-09 07:23

    arduino關(guān)鍵字資料

    arduino關(guān)鍵字
    發(fā)表于 04-23 10:46 ?7次下載

    java中static關(guān)鍵字的作用

    static關(guān)鍵字是很多朋友在編寫代碼和閱讀代碼時(shí)碰到的比較難以理解的一個(gè)關(guān)鍵字,也是各大公司的面試官喜歡在面試時(shí)問到的知識點(diǎn)之一。下面就先講述一下static關(guān)鍵字的用法和平常容易誤解的地方,最后
    發(fā)表于 09-27 17:12 ?0次下載

    Keil自定義關(guān)鍵字、 快捷鍵···

    Keil自定義關(guān)鍵字、快捷鍵···
    的頭像 發(fā)表于 03-12 11:33 ?4802次閱讀

    C語言:結(jié)構(gòu)體、聯(lián)合體嵌套使用的實(shí)用操作

    ? 結(jié)構(gòu)體、聯(lián)合體是C語言中的構(gòu)造類型,結(jié)構(gòu)體我們平時(shí)應(yīng)該都用得很多。但是,對于聯(lián)合體,一些初學(xué)的朋友可能用得并不多,甚至感到陌生。我們先簡單看一下聯(lián)合體: 在C語言中定義聯(lián)合體的關(guān)鍵字union
    的頭像 發(fā)表于 12-24 16:07 ?5373次閱讀
    C語言:結(jié)構(gòu)體、聯(lián)合體嵌套使用的實(shí)用操作

    基于關(guān)鍵字的自定義古詩句生成設(shè)計(jì)與實(shí)現(xiàn)

    Seq2Seq模型,通過自建的數(shù)據(jù)集進(jìn)行訓(xùn)練,實(shí)現(xiàn)了基于關(guān)鍵字的自定乂古詩句生成。在生成階段,首先輸入一段描述性內(nèi)容,并從中提取岀關(guān)鍵字。當(dāng)關(guān)鍵字不足時(shí),使用word2vec進(jìn)行有效的關(guān)鍵字
    發(fā)表于 04-12 15:30 ?20次下載
    基于<b class='flag-5'>關(guān)鍵字</b>的自<b class='flag-5'>定義</b>古詩句生成設(shè)計(jì)與實(shí)現(xiàn)

    python語言之使用async關(guān)鍵字定義函數(shù)

    早期的協(xié)程是用yield來實(shí)現(xiàn)的,但是代碼特別難懂, python3.5之后的版本, 使用 async 關(guān)鍵字定義的函數(shù)。調(diào)用該函數(shù),會返回一個(gè)協(xié)程對象
    的頭像 發(fā)表于 08-24 11:12 ?2624次閱讀

    ARM中關(guān)鍵字的具體使用

    奇怪。之前對于 __weak 關(guān)鍵字一直是一個(gè)簡單的認(rèn)知:「編譯器自動(dòng)使用沒有 __weak 的同名函數(shù)(如果有的話)替換有 __weak 關(guān)鍵字的同名函數(shù),__weak 函數(shù)可以沒有定義,且編譯器
    的頭像 發(fā)表于 02-10 15:06 ?1084次閱讀

    const關(guān)鍵字應(yīng)用總結(jié)

    C++中的const關(guān)鍵字的用法非常靈活,而使用const將大大改善程序的健壯性
    的頭像 發(fā)表于 05-26 09:06 ?493次閱讀

    LL庫中常見關(guān)鍵字__STATIC_INLINE

    LL庫中常見關(guān)鍵字__STATIC_INLINE,其定義見cmsis_gcc.h
    的頭像 發(fā)表于 07-24 11:30 ?1216次閱讀
    LL庫中常見<b class='flag-5'>關(guān)鍵字</b>__STATIC_INLINE

    快速掌握C語言關(guān)鍵字

    C語言中的32個(gè)關(guān)鍵字你知道多少個(gè)呢?根據(jù)關(guān)鍵字的作用分為四類:數(shù)據(jù)類型關(guān)鍵字、控制語句關(guān)鍵字、存儲類型關(guān)鍵字和其它
    的頭像 發(fā)表于 07-06 08:04 ?194次閱讀
    快速掌握C語言<b class='flag-5'>關(guān)鍵字</b>