union的⽤法以及struct的初始化
在C/C++程序的编写中,当多个基本数据类型或复合数据结构要占⽤同⼀⽚内存时,我们要使⽤联合体;当多种类型,多个对象,多个事物
只取其⼀时(我们姑且通俗地称其为“n选1”),我们也
可以使⽤联合体来发挥其长处。⾸先看⼀段代码:
unionmyun
{
struct{intx;inty;intz;}u;
intk;
}a;
intmain()
{
a.u.x=4;
a.u.y=5;
a.u.z=6;
a.k=0;
printf("%d%d%dn",a.u.x,a.u.y,a.u.z);
return0;
}
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是Littleendian还是Bigendian模式?
分析:
作为⼀个计算机相关专业的⼈,我们应该在计算机组成中都学习过什么叫Littleendian和Bigendian。Littleendian和Bigendian是CPU存
放数据的两种不同顺序。对于整型、长整型等数据类型,Bigendian认为第⼀个字节是最⾼位字节(按照从低地址到⾼地址的顺序存放数据
的⾼位字节到低位字节);⽽Littleendian则相反,它认为第⼀个字节是最低位字节(按照从低地址到⾼地址的顺序存放数据的低位字节到
⾼位字节)。
例如,假设从内存地址0x0000开始有以下数据:
0x120x340xab0xcd
如果我们去读取⼀个地址为0x0000的四个字节变量,若字节序为big-endian,则读出结果为0x1234abcd;若字节序位little-endian,则读出
结果为0xcdab3412。如果我们将0x1234abcd写⼊到以0x0000开始的内存中,则Littleendian和Bigendian模式的存放结果如下:
地址0x00000x00010x00020x0003
big-endian0x120x340xab0xcd
little-endian0xcd0xab0x340x12
⼀般来说,x86系列CPU都是little-endian的字节序,PowerPC通常是Bigendian,还有的CPU能通过跳线来设置CPU⼯作于Little
endian还是Bigendian模式。
解答:
显然,解答这个问题的⽅法只能是将⼀个字节(CHAR/BYTE类型)的数据和⼀个整型数据存放于同样的内存
开始地址,通过读取整型数据,分析CHAR/BYTE数据在整型数据的⾼位还是低位来判断CPU⼯作于Little
endian还是Bigendian模式。得出如下的答案:
typedefunsignedcharBYTE;
intmain(intargc,char*argv[])
{
unsignedintnum,*p;
p=#
num=0;
*(BYTE*)p=0xff;
if(num==0xff)
{
printf("Theendianofcpuislittlen");
}
el//num==0xff000000
{
printf("Theendianofcpuisbign");
}
return0;
}
除了上述⽅法(通过指针类型强制转换并对整型数据⾸字节赋值,判断该赋值赋给了⾼位还是低位)外,还有没
有更好的办法呢?我们知道,union的成员本⾝就被存放在相同的内存空间(共享内存,正是union发挥作⽤、做贡献的去处),因此,我
们可以将⼀个CHAR/BYTE数据和⼀个整型数据同时作为⼀个union的成员,得出
如下答案:
intcheckCPU()
{
{
unionw
{
inta;
charb;
}c;
c.a=1;
return(c.b==1);
}
}
实现同样的功能,我们来看看Linux操作系统中相关的源代码是怎么做的:
staticunion{charc[4];unsignedlongmylong;}endian_test={{'l','?','?','b'}};
#defineENDIANNESS((char)endian_)
Linux的内核作者们仅仅⽤⼀个union变量和⼀个简单的宏定义就实现了⼀⼤段代码同样的功能!由以上⼀段代码我们可以深刻领会到Linux
源代码的精妙之处!(如果ENDIANNESS=’l’表⽰系统为littleendian,
为’b’表⽰bigendian)
试题⼆:假设⽹络节点A和⽹络节点B中的通信协议涉及四类报⽂,报⽂格式为“报⽂类型字段+报⽂内容的结构体”,四个报⽂内容的结构体
类型分别为STRUCTTYPE1~STRUCTTYPE4,请编写程序以最简单的⽅式组
织⼀个统⼀的报⽂数据结构。
分析:
报⽂的格式为“报⽂类型+报⽂内容的结构体”,在真实的通信中,每次只能发四类报⽂中的⼀种,我们可以将四类报⽂的结构体组织为⼀个
union(共享⼀段内存,但每次有效的只是⼀种),然后和报⽂类型字段统⼀组织成⼀个报⽂数据结构。
解答:
根据上述分析,我们很⾃然地得出如下答案:
typedefunsignedcharBYTE;
//报⽂内容联合体
typedefuniontagPacketContent
{
STRUCTTYPE1pkt1;
STRUCTTYPE2pkt2;
STRUCTTYPE3pkt1;
STRUCTTYPE4pkt2;
}PacketContent;
//统⼀的报⽂数据结构
typedefstructtagPacket
{
BYTEpktType;
PacketContentpktContent;
}Packet;
写了⼀个⼩例⼦,将union和struct相结合。
#include
structend{
intend;
union{
charc;
intk;
}myun;
/*unionmyun{
charc;
intk;
}a;struct中的union可以⽤这两种⽅法来声明*/
};
intmain()
{
structendend1={
.end=24,
.myun={'k'},
};//注意struct的初始化,各个成员初始化完毕之后使⽤‘,’⽽不是‘;’。
printf("%d%c%dn",,.c,.k);
return0;
}
本文发布于:2022-12-28 06:30:00,感谢您对本站的认可!
本文链接:http://www.wtabcd.cn/fanwen/fan/90/45199.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |