实用经验 15 既有结构,为何引入联合?

Struct结构体由一系列相同类型或不同类型的数据构成的数据集合。结构体也成结构。结构体的一般定义形式如下:

struct 结构体名称
{
    成员表列
}变量表列;

例如:

/* 定义一个名称为Person的结构体*/
struct Person 
{
    char *pszName;  /*Person的名称*/
    int   iSex;       /*Person的性别*/
}Boy; // 定义一个名称为Boy的变量

Union联合由几个不同的变量存放在同一块区域内,也就是覆盖技术。几个变量互相覆盖。Union联合的一般定义形式如下:

union 结构体名称
{
    成员表列
}变量表列;

例如:

/* 在用一位置存放1 字和2个字节*/
union WordToByte 
{ 
    unsigned char Tbyte[2]   ;/* Tbyte[0] 是Tword的低字节 */
    unsigned short Tword;    /* Tbyte[1] 是Tword的高字节 */
}Word;

从定义形式上看,“联合”和“结构体”非常形似。但两者在本质上还是差异很大的。首先,在结构体中每个成员都有自己的内存,一个结构体变量的总长度等于各个成员长度的总和。而联合呢。在联合中,各个成员共享一段内存空间,一个联合变量的长度等于各个成员中长度最大的那个成员的长度。联合体对数据的引用同结构体对数据的引用方式相同。都必须通过联合或结构体中的元素引用,而不能引用联合体变量。

例如,针对上述定义的联合体变量Word下面的操作就是错误的。

printf("%d", Word);  <==  这种用法是错误的。

说明
联合体的共享不是指把过个成员同时装入一个联合体内,而是数据根据联合体的定义可以展现成不同的形式。同时向用户传递不同讯息的过程。

联合体,一般有下述几个特点:

  • 同一个联合体,可用来存放几种不同类型的成员,但是在每一瞬间只能存放其中的一种,而不是同时存放几种。换句话说,每一瞬间只有一个成员起作用,其他的成员不起作用,即不是同时都在存在和起作用。
  • 共用体变量中起作用的成员是最后一次存放的成员,在存入一个新成员后,原有成员就失去作用。
  • 共用体变量的地址和它的各成员的地址都是同一地址。
  • 不能对共用体变量名赋值,也不能企图引用变量名来得到一个值,并且也不能在定义共用体变量时对它进行初始化。
  • 不能把共用体变量作为函数参数,也不能最为函数的返回值,但可使用指向共用体变量的指针。
  • 共用体类型可出现在结构体类型的定义中,也可定义共用体数组。反之,结构体也可出现在共用体类型的定义中,数组也可作为共用体的成员。

最后,我们来看一下联合体的两种经典的应用场景。一种是通过联合体判断操作系统,或者CPU的特征;第二种是同样的数据采用不用的展现方式,会使我们获取的信息更清晰明了。

首先看第一种,获取操作系统或者CPU特征,我们经常会碰到这样的问题,在网络传输中数据都是采用大端传输的,而我们不知道服务器CPU采用的格式是大端的还是小端的,在编写服务器处理程序时有时会遇见数据解析错误的现象。采用联合体可方便获取CPU的大小端特征。

union w
{
    int a;  //4 bytes
    char b; //1 byte
} c;

c.a = 1;
if (c.b==1)
{
    printf("此CPU是小端CPU\n");
}
else
{
    printf("此CPU是大端CPU\n");
}

接着,我们将是采用联合体实现数据的展示,同样以网络数据为例。在网络中数据都是以流的形式传输,而当到达服务器时,数据流就会以不同的形式解析。典型的就是包头的解析。我们看一个链路层数据报头通过联合处理后数据的展示。

// 网络数据,全部是16进制数据。不方便报文的分析和查看。
szData[] = {
        0x70,0x1a,0x04,0xae,0x2f ,0x0f ,0x40,0x16,0x9f,0xd6 ,0x62,0x8a,0x08,0x00,0x45,0x00,
        0x00,0x2c,0x45,0x62,0x00,0x00,0x32,0x11,0xa4,0xa9,0xdb,0x8f,0x01,0x1a,0xc0,0xa8,
        0x01,0x64,0xaa,0xd0,0x11,0x72,0x00,0x18,0x55,0x5b,0x4b,0x55,0x00,0x01,0x04,0x00,
        0x00,0x08,0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x09
};

// 链路层MAC数据报头的定义
struct eth_hdr  
{
    struct eth_addr dest;   //目标 MAC 地址
    struct eth_addr src;    //源MAC 地址
    u16_t type;             //类型
};
union ETH_HDR              // ether 头联合体
{
    char *pszMacData;
    eth_hdr ethhdr;
}

ETH_HDR ethHDR;
memset(&ethHDR, 0sizeof(ETH_HDR));
ethHDR.pszMacData = szData;       // szData代表网络上读取的数据。

通过ethHDR.ethhdr. type方便查看MAC报文头中的类型数据。

请谨记

  • 联合体虽然和结构体长得很像,但是两者还是有本质区别的。在使用时请区别看待。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值