c++ unio 学习总计

c++的 union类型平时用的真心少 从来没有认真研究过他

今天看了几道c++的笔试题   有几道 关于union的 题目  现在总结下

第一题:

union V {
struct X {
unsigned char s1:2;
unsigned char s2:3;
unsigned char s3:3;
} x;
unsigned char c;
} v;
v.c = 100;
printf("%d", v.x.s3);


答案为 3  (s2 为 1   ,  s1为0)

网上的解释

v是联合体(共用体)变量,共有两个元素x和c,都需要一个字节,它们分配于同一个地址。

而x是结构体变量,共有三个元素s1、s2、s3,分别占2位、3位、3位。分配内存时低位在前,最位在后。

当有v.c=100(其二进制为01100100)时,各变量的关系及内存存储情况见图所示。
其中x的成员s3为二进制的011,即十进制的3,所以输出结果为3。


同理的第二题:

#i nclude <stdio.h>
union
{
int i;
char x[2];
}a;
void main()
{
a.x[0] = 10;
a.x[1] = 1;
printf("%d",a.i);
}
int 为 .. ...  0000 0001  0000 0010  

答案:266 (低位低地址,高位高地址,内存占用情况是Ox010A)


学习中 看了些文章 有所收获 下面转两篇文章 


一篇是 union和struct的 大小问题

1,对于union,对齐的大小是最大的基本元素的对齐大小;对象的大小必须是该基本元素大小的整数倍;
2,对于struct,对齐的大小也是最大的基本元素的对齐大小,对象的大小需要考虑元素的对齐,并且需要是最大基本元素的整数倍;同时有#pragma pack修饰的情况,关于struct请详细参考另外一个帖子。
3,这里所说的struct和union的对齐,是指其作为其他复杂对象中的元素的时候要求的对齐,对于本身大小的计算并没有关系。本身的大小只和其所包含的基本元素的对齐有关系。

(copy 一段网上的对齐规则 1,数据成员对齐规则:结构的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小的整数倍开始(比如int在32位机为4字节,则要从4的整数倍地址开始存储) 2,,结构体作为成员:如果一个结构体里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储(struct a里存有 stuct b, b里有char,int,double等元素,那么b应该从8的整数倍开始存储) 3,收尾工作:结构体的总大小,也就是sizeof的结果,必须是其内部最大成员的整数倍,不足的要补齐。)
例子一:
union U1
{
 char a[9]; //对齐大小是1,大小是9个字节
 int b; //对齐大小是4,大小是4个字节
};
所以该union的对齐大小是4个字节;大小为大于等于max(9,4)=9并为4的整数倍,所以是12字节。


例子二:
union U1_Another
{
 char a[9]; //对齐大小是1,大小是9个字节
 double b; //对齐大小是8,大小是8个字节
};
所以该union的对齐大小是8个字节,大小是大于等于9并为8的整数倍,即为16字节;


例子三:
union U2
{
 U1 a; //对齐大小是4个字节,大小是12字节
 double b; //对齐大小是8个字节,大小是8字节
};
所以该union的对齐大小是8个字节,大小是16;


例子四:
struct S1
{
 char a[13]; //对齐大小是1字节,位置是[0,12]
 double c; //对齐大小是8字节,位置是[16,23]
}
所以该结构体是8字节对齐,大小为24个字节;


另一篇是 union和大小端模式 :

一.union数据类型

union顾名思义,联合体,float,int,char等等类型数据共用一块内存空间。其大小为占据内存空间最大的那个变量的空间大小。

eg:

union

{

 float a;

 char b[2];

}u_test;

那么union所占的内存空间大小为float类型变量a所占的内存大小,在常见32位计算机上为4字节。

 

二.大小端对union的影响

一般x86体系的计算机采用的是小端模式:高高低低,高字节数据存放在内存中的高地址处,低字节数据存放在内存中的低地址处。

反之,大端模式就是高低高低了,高字节数据存放在内存中的低地址处,低字节数据存放在内存中的高地址处。

 

16bit宽的数0x1234Little-endian模式(以及Big-endian模式)CPU内存中的存放方式(假设从地址0x4000开始存放)为:

 

内存地址

小端模式存放内容

大端模式存放内容

0x4000

0x34

0x12

0x4001

0x12

0x34

说明:内存中最小的单位为1字节(8bit),上表中的0x4000正是这样一个字节内存,显然相对于0x4001而言,0x4000是低地址。低字节数据0x34就存放于内存的低地址0x4000处,而高字节数据0x12就存放于内存的高地址0x4001处。

 

32bit宽的数0x12345678Little-endian模式以及Big-endian模式)CPU内存中的存放方式(假设从地址0x4000开始存放)为:

内存地址

小端模式存放内容

大端模式存放内容

0x4000

0x78

0x12

0x4001

0x56

0x34

0x4002

0x34

0x56

0x4003

0x12

0x78

 

三.测试大小端对union的影响,假设union分配的内存地址首地址为0,

eg:

union u_test

{

  int a;

  char b[2];

}mm;

写一个测试函数:

void test_union(void)

{

       mm.a = 65*256 + 97;   

       printf("union's b[0] is: %c,b[1] is: %c\n",mm.b[0],mm.b[1]);

}

这个结构体的大小为int a的大小4字节。假设在内存中是从地址0开始的连续4个单位。显然这4个字节的内存块的存放着a的值。则按照高高低低的原则,低内存地址0应该存放的是低字节数据97,依此往下存放,即内存地址为1的内存单元存放着十进制数为65的数据,内存地址为2的内存单元存放着0,内存地址为3的内存单元存放着0

内存地址

小端模式存放内容

0

存放着十进制97

1

存放着十进制65

2

0

3

0

所以上面的函数test_union执行的结果将会是打印小写字母a(97)和大写字母A(65).

那如果是大端模式将会是怎样的结果呢?如下:

内存地址

大端模式存放内容

0

0

1

0

2

十进制65

3

十进制97

 

.测试CPU是大端还是小端模式?

当然对于一般的CPU,我们已经了解到:

Big Endian : PowerPCIBMSun

Little Endian : x86DEC

ARM既可以工作在大端模式,也可以工作在小端模式。

如果不知平台到底运行于何种模式,也根据上面的这些特性可以自己测试出来?

  1. /*
  2. ** 函数名:checkCPU
  3. ** 输 入:none
  4. ** 输 出:0-- 大端模式
  5. ** 1-- 小端模式
  6. ** 功 能:检测CPU的大小端模式
  7. */
  8. int checkCPU(void)
  9. {
  10.   union check
  11.   {
  12.     int i;
  13.     char j;
  14.   }c;

  15.   c.= 1;

  16.   return (c.== 1);
  17. }

注: union 为低地址对齐 如果是 little 则int 为  01 00 00 00 然后 j 对齐低地址 为01 所以c.j==1

       如果为big为 00 00 00 01  然后j对齐低地址 为 00 所以c.j==0

或者:

bool IsBigendian()
{
    unsigned short usData = 0x1122;
    unsigned char *pucData = (unsigned char*)&usData;
    return (*pucData == 0x11);
}
注: 转换 也是从地地址开始处理 若为 little usData 存为 22 11  pucData从低地址开始获取 则为 22

                                                        若为 big  usData存为 11 22 pucData从低地址开始获取 则为 11


你可能感兴趣的:(c++ unio 学习总计)