`

C语言中的联合体union

阅读更多
C语言中的联合体union
http://blog.csdn.net/s04023083/archive/2010/01/11/5173397.aspx
引用

在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

再看两个试题:
试题一:编写一段程序判断系统中的CPU 是Little endian 还是Big endian 模式?
分析:
作为一个计算机相关专业的人,我们应该在计算机组成中都学习过什么叫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;
}
除了上述方法(通过指针类型强制转换并对整型数据首字节赋值,判断该赋值赋给了高位还是低位)外,还有没
有更好的办法呢?我们知道,union 的成员本身就被存放在相同的内存空间(共享内存,正是union 发挥作用、做贡献的去处),因此,我们可以将一个CHAR/BYTE 数据和一个整型数据同时作为一个union 的成员,得出
如下答案:
int checkCPU()
{
{
  union w
{
  int a;
  char b;
} c;
c.a = 1;
return (c.b == 1);
}
}
实现同样的功能,我们来看看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 )
试题二:假设网络节点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;



分享到:
评论

相关推荐

    C语言中联合体union的实例详解

    C语言中联合体union的实例详解 1.定义: union(int i, short s, char c) un; un.i = 3; printf(“i=%d”,un.i); printf(“length = %d\n”,sizeof(un);//==4,有最大的变量来决定 2.相当与java里的List T类型 3....

    C语言编程中的联合体union入门学习教程

    联合体(union)在C语言中是一个特殊的数据类型,能够存储不同类型的数据在同一个内存位置。可以定义一个联合体使用许多成员,但只有一个部件可以包含在任何时候给定的值。联合体会提供使用相同的存储器位置供多用途的...

    C语言深层探索+ARM linux移植

    C/C+语言struct深层探索 ...从两道经典试题谈C/C++中联合体(union)的使用 149 深入浅出Linux设备驱动编程 151 1.Linux内核模块 151 2.字符设备驱动程序 153 3.设备驱动中的并发控制 158 4.设备的阻塞与非阻塞操作 165

    C语言 共用体(Union)详解及示例代码

    在C语言中,还有另外一种和结构体非常类似的语法,叫做共用体(Union),它的定义格式为: union 共用体名{  成员列表 }; 共用体有时也被称为联合或者联合体,这也是 Union 这个单词的本意。 结构体和共用体的...

    初步剖析C语言编程中的结构体.doc

    C语言结构体,可谓是C强大...C语言中,结构体的声明、定义是用到关键字struct,就像联合体用到关键字union、枚举类型用到enum关键字一样,事实上,联合体、枚举类型的用法几乎是参照结构体来的。结构体的声明格式如下:

    嵌入式C语言精华+.pdf

    从两道经典试题谈 C/C++中联合体(union)的使用 ......................................................81 基于 ARM 的嵌入式 Linux 移植真实体验 ...............................................................

    计算机二级c语言资料.zip

    构造数据类型:数组、结构体(struct)、联合体(union)、枚举(enum) 指针类型:指向各种数据类型的指针 空类型(void) 运算符与表达式 算术运算符:加(+)、减(-)、乘(*)、除(/)、取模(%) 关系运算符...

    嵌入式系统C语言精华

    从两道经典试题谈C/C++中联合体(union)的使用......................................................81 基于ARM 的嵌入式Linux 移植真实体验...................................................................

    c语言资料-c嵌入式C精华

    从两道经典试题谈 C/C++中联合体(union)的使用......................................................81 基于 ARM 的嵌入式 Linux 移植真实体验 ...............................................................

    FakeCc:自制编译器FakeCc

    实现了c语言的基本数据类型,除掉了union联合体类型,增加了boolean类型; 更改了c语言中数组的定义顺序,由char a[10]改成了char[10] a; 实现了指针的功能,指针与指针不能进行加减运算,能和整数类型进行基本运算; 实现...

    标准MFC WinSock ActiveX控件开发实例

    后面看到各种变量类型包括在一个联合体当中,也就是说指明vt后,你只能使用对应的其中之一变量类型。看着这众多的各种不同 类型变量集中在一起,确实让人吓了一跳,但细细看来,大多数变量跟我们平时的用法相似。...

    南方科技大学计算机系C++程序设计.rar

    今天写写最近学习的C++课程笔记...数组(一维数组,定长数组,变长数组,多维数组,常量数组等等,字符串string),结构体(struct)【将不同的数据类型统一起来,用法基本上同后面学到的类】,联合体(union)【共享同一

    嵌入式C/C++语言开发精华文章集锦(嵌入式C/C++开发者必看,很有价值的文章)

    从两道经典试题谈 C/C++中联合体(union)的使用. 基于 ARM 的嵌入式Linux 移植真实体验 基于 ARM 的嵌入式Linux 移植真实体验(1)――基本概念 基于 ARM 的嵌入式Linux 移植真实体验(2)――BootLoader 基于 ARM...

    嵌入式C_C++语言精华.pdf

    从两道经典试题谈 C/C++中联合体(union)的使用......................................................81 基于 ARM 的嵌入式 Linux 移植真实体验 ..............................................................

    嵌入式C_C++语言精华文章集锦

    从两道经典试题谈C/C++中联合体(union)的使用......................................................81 基于ARM的嵌入式Linux移植真实体验................................................................83...

    嵌入式C精华.pdf

    从两道经典试题谈 C/C++中联合体(union)的使用......................................................81 基于 ARM 的嵌入式Linux 移植真实体验..................................................................

Global site tag (gtag.js) - Google Analytics