一、共用体概述
共用体是一种自定义数据类型,它的定义格式为:
union 共用体名
{
成员列表
};
结构体和共用体的区别在于:
- 结构体的各个成员会占用不同的内存,互相之间没有影响;
- 共用体的所有成员共享同一段内存,同一时间只能储存其中一个数据成员,共用体所占的空间不仅取决于最宽成员,还跟所有成员有关系,即其大小必须满足两个条件:1)大小足够容纳最宽的成员;2)大小能被其包含的所有基本数据类型的大小所整除。
- 所有的数据成员具有相同的起始地址(即固定首地址)。
一段测试代码如下:
#include<stdio.h>
union U1
{
char s[9];
int n;
double d;
float f;
};
union U2
{
char s[9];
int n;
float f;
};
int main(void)
{
printf("%d\r\n",sizeof(double));//8
printf("%d\r\n",sizeof(float));//4
printf("%d\r\n",sizeof(int));//4
printf("%d\r\n",sizeof(union U1));//16
printf("%d\r\n",sizeof(union U2));//12
return 0;
}
二、共用体妙用
对同一个内存单元进行多种不同规则解析
union U1
{
char s[4];
float f;
};
三、共用体使用陷阱
对比如下两段代码:
typedef union
{
uint32_t word;
uint8_t bytes[4];
}word_msg_t;
unit32_t read_mesg(void)
{
word_rnsg_t tmp;
/*注:tmn bvte[O]对府干tmp.word的高8位,tmp byter[l]对应于tmp.WOfO的次高8位,依次类*/
tmp.bytes[O]=read_byte();
tmp.bytes[1]=read_byte();
tmp.bytes[2]=read_byte();
tmp.bytes[3]=read_byte();
retern(trap.word);
}
以上代码格式在各种通信协议中使用的频率很高,接收端接收到的数据一般都以字节为单位存放,主控程序需要根据相应的协议将接收到的多个字节进行组合。为了实现相同的功能,《MISRA-C:2004》推荐了read_msg()函数的另外一种写法。
uint32_trcad_msg(void)
{
uint32_t word;
Word=((unit32_t)read_byte())<<24;
word=word│(((unit32_t)read_byte())<<16);
word=word│(((unit32_t)read_byted_byte<<8);
word=word│(((unit32_t)read_byte());
return(word):
}
无论从程序的清晰程度还是执行效率来讲,程序段1都优于程序段2。然而,程序段1在不同的平台上运行结果是不同的(涉及到大小端的问题)假设read_byte()函数返回的数据依次是0x01、0x02、0x03和0x04,则在Intel体系中,程序段1中read_msg()函数的返回值是0x432l;在Motorola体系中,read_msg()的返回值是0x1234。
但无论在Intel体系还是Motorola体系中,程序2中read_msg()的返回值都是0x1 234。
以上是联合体中多字节整型字节排放顺序不定导致漏洞的一个例子。
REF:
https://blog.csdn.net/weixin_34409822/article/details/86037807