c中的union的用法和做用

在C/C++程序的编写中,当多个基本数据类型或复合数据结构要占用同一片内存时,咱们要使用联合体;当多种类型,多个对象,多个事物只取其一时(咱们姑且通俗地称其为“n 选1”),咱们也能够使用联合体来发挥其长处。
首先看一段代码:
union myun {   struct { int x; int y; int z; }u;   int k; }a; int main() {   a.u.x =4;   a.u.y =5;   a.u.z =6;   a.k = 0;   printf("%d %d %d\n",a.u.x,a.u.y,a.u.z);   return 0; }

union类型是共享内存的,以size最大的结构做为本身的大小,这样的话,myun这个结构就包含u这个结构体,而大小也等于u这个结构体 的大小,在内存中的排列为声明的顺序x,y,z从低到高,而后赋值的时候,在内存中,就是x的位置放置4,y的位置放置5,z的位置放置6,如今对k赋 值,对k的赋值由于是union,要共享内存,因此从union的首地址开始放置,首地址开始的位置实际上是x的位置,这样原来内存中x的位置就被k所赋的 值代替了,就变为0了,这个时候要进行打印,就直接看内存里就好了,x的位置也就是k的位置是0,而y,z的位置的值没有改变,因此应该是0,5,6网络

当程序变成:
union myun {   struct { int x; int y; int z; }u;   int k;   int j; }a; int main() {   a.u.x =4;   a.u.y =5;   a.u.z =6;   a.k = 0;   a.j = 1;   printf("%d %d %d\n",a.u.x,a.u.y,a.u.z);   return 0; }

结果为1,5,6 由于仍是从最低的地址开始覆盖,而不是像有些人想象的是 0,1,6数据结构

 

再看两个试题:
试题一:编写一段程序判断系统中的CPU 是Little endian 仍是Big endian 模式?
分析:
Little endian 和Big endian 是CPU 存放数据的两种不一样顺序。对于整型、长整型等数据类型,Big endian 认为第一个字节是最高位字节(按照从低地址到高地址的顺序存放数据的高位字节到低位字节);而Little endian 则相反,它认为第一个字节是最低位字节(按照从低地址到高地址的顺序存放数据的低位字节到高位字节)。
例如,假设从内存地址0x0000 开始有如下数据:
0x12 0x34 0xab 0xcd
若是咱们去读取一个地址为0x0000 的四个字节变量,若字节序为big-endian,则读出结果为0x1234abcd;若字节序位little-endian,则读出结果为0xcdab3412。若是咱们将0x1234abcd 写入到以0x0000 开始的内存中,则Little endian 和Big endian 模式的存放结果以下:
地址               0x0000 0x0001 0x0002 0x0003
big-endian         0x12   0x34   0xab   0xcd
little-endian      0xcd   0xab   0x34   0x12
通常来讲,x86 系列CPU 都是little-endian 的字节序,PowerPC 一般是Big endian,还有的CPU 能经过跳线来设置CPU 工做于Little endian 仍是Big endian 模式。
解答:
显然,解答这个问题的方法只能是将一个字节(CHAR/BYTE 类型)的数据和一个整型数据存放于一样的内存开始地址,经过读取整型数据,分析CHAR/BYTE 数据在整型数据的高位仍是低位来判断CPU 工做于Little endian 仍是Big endian 模式。
得出以下的答案:
typedef unsigned char BYTE; int main(int argc, char* argv[]) {   unsigned int num,*p;   p = #   num = 0;   *(BYTE *)p = 0xff;   if(num == 0xff)   {     printf("The endian of cpu is little\n");   }   else //num == 0xff000000
  {     printf("The endian of cpu is big\n");   }   return 0; }

除了上述方法(经过指针类型强制转换并对整型数据首字节赋值,判断该赋值赋给了高位仍是低位)外,还有没有更好的办法呢?spa

咱们知道,union 的成员自己就被存放在相同的内存空间(共享内存,正是union 发挥做用、作贡献的去处),所以,咱们能够将一个CHAR/BYTE 数据和一个整型数据同时做为一个union 的成员,得出以下答案:操作系统

int checkCPU() { {
 union w   {   
int a;   char b;   } c;   c.a = 1;   return (c.b == 1); } }

返回1表示是:Little endian,0表示:Big endian指针


实现一样的功能,咱们来看看Linux 操做系统中相关的源代码是怎么作的:
static union { char c[4]; unsigned long mylong; } endian_test = {{ 'l', '?', '?', 'b' } }; #define ENDIANNESS ((char)endian_test.mylong)

Linux 的内核做者们仅仅用一个union 变量和一个简单的宏定义就实现了一大段代码一样的功能!由以上一段代码咱们能够深入领会到Linux 源代码的精妙之处!(若是ENDIANNESS=’l’表示系统为little endian, 为’b’表示big endian )code

 

试题二:假设网络节点A 和网络节点B 中的通讯协议涉及四类报文,报文格式为“报文类型字段+报文内容的结构体”,四个报文内容的结构体类型分别为STRUCTTYPE1~ STRUCTTYPE4,请编写程序以最简单的方式组
织一个统一的报文数据结构。

分析:
报文的格式为“报文类型+报文内容的结构体”,在真实的通讯中,每次只能发四类报文中的一种,咱们能够将四类报文的结构体组织为一个union(共享一段内存,但每次有效的只是一种),而后和报文类型字段统一组织成一个报文数据结构。
解答:
根据上述分析,咱们很天然地得出以下答案:
typedef unsigned char BYTE;
//报文内容联合体
typedef union tagPacketContent
{
  STRUCTTYPE1 pkt1;
  STRUCTTYPE2 pkt2;
  STRUCTTYPE3 pkt1;
  STRUCTTYPE4 pkt2;
}PacketContent;
//统一的报文数据结构
typedef struct tagPacket
{
  BYTE pktType;
  PacketContent pktContent;
}Packet;
本文为转载,出处已不详,感谢原做者!
相关文章
相关标签/搜索