以下数据来自于Dev CPP
首先呈现实际测试数据:
主程序如下:
2 #include <iostream>
3
4 using namespace std;
5
6 typedef struct s1 {
7 //char ch, *ptr;
8 union {
9 short a, b;
10 //unsigned int c:2, d:1;
11 };
12 };
13 //struct s1 *next;
14 //};
15
16 int main()
17 {
18 printf("%d\n",sizeof(s1));
19 system("pause");
20 return 1;
21 }
下面的测试数据,通过不断修改struct的结构体内容,来达到不同的测试结果。
2 //char ch, *ptr;
3 union {
4 short a, b;
5 //unsigned int c:2, d:1;
6 };
7 };
以上测试样例一输出答案:2
2 char ch, *ptr;
3 //union {
4 //short a, b;
5 //unsigned int c:2, d:1;
6 // };
7 };
以上测试样例二输出答案:8
2 char ch;//, *ptr;
3 //union {
4 //short a, b;
5 //unsigned int c:2, d:1;
6 // };
7 };
以上测试样例三输出答案:1
2 char ch, *ptr;
3 union {
4 //short a, b;
5 //unsigned int c:2, d:1;
6 };
7 };
以上测试样例四输出结果:12
2 char ch, *ptr;
3 union {
4 short a, b;
5 //unsigned int c:2, d:1;
6 };
7 };
以上测试样例五输出答案:12
2 char ch, *ptr;
3 union {
4 short a, b;
5 unsigned int c:2, d:1;
6 };
7 };
以上测试样例六输出答案:12
2 //char ch, *ptr;
3 union {
4 short a, b;
5 unsigned int c:2, d:1;
6 };
7 };
以上测试样例七输出答案:4
2 //char ch, *ptr;
3 union {
4 //short a, b;
5 unsigned int c:2, d:1;
6 };
7 };
以上测试样例八输出答案:4
2 //char ch, *ptr;
3 union {
4 //short a, b;
5 //unsigned int c:2, d:1;
6 };
7 };
以上测试样例九输出答案:1
通过上述实验结果而知,首先对于32bits的PC来说,定义下:
char,uchar 1个字节
int uint 4个字节
union一个字节
上述是前提,供后续分析使用。
首先是字节对齐的问题,何为字节对齐?
个人认为字节对齐主要是因为两个方面的原因:
- 统一标准,进行不同设备间的通讯,比如:异构CPU,异构内存模型等等
- 加速数据的访问,字节对齐能使得取值,save等操作更加方便,因为存储时起始地址都是对齐后的地址。
那么非结构体时,无需考虑sizeof后的效果,因为原生态的类型,在存储时占用大小一致,只是原生态的变量间会有不同的填充空间。
下面只是分析结构体内的处理方式,下面是几个原则:
- 结构体对齐存在结构体内对齐,结构体对齐两个部分。
- 结构体内每个变量存放的其实地址必须是自己所用大小的整数倍。
- 结构体对齐需要结构体的长度是结构体内最大占用变量的长度的整数倍。
- union占用一个字节,内部变量共享所有的内存。
下面利用上述三个原则来重新分析下上述实验结果。
2 //char ch, *ptr;
3 union {
4 short a, b;
5 //unsigned int c:2, d:1;
6 };
7 };
以上测试样例一输出答案:2
union共享内存,也就是说a b两个变量共享内存,short在32bits机器中是双字节变量,所以长度为2;
结构体对齐:目前内部长度是2,内部最大变量也是2,所以是整数倍。不需要结构体对齐。最终结果是2;
2 char ch, *ptr;
3 //union {
4 //short a, b;
5 //unsigned int c:2, d:1;
6 // };
7 };
以上测试样例二输出答案:8
结构体内有两个变量,char char*
首先char型占用一个字节,char*指针占用四个字节。
指针需要从addr%4==0的地址开始,所以char---char*之间系统需要补充3个字节。
所以char+char*后的长度是8,最长的内部变量长度是char*=4个,所以满足结构体对齐,不需要结构体调整。
所以最终长度是8。
2 char ch;//, *ptr;
3 //union {
4 //short a, b;
5 //unsigned int c:2, d:1;
6 // };
7 };
以上测试样例三输出答案:1
简单的char是1个字节,结构体内长度=1,最长变量长度也是1,所以满足条件,无需结构体调整。
2 char ch, *ptr;
3 union {
4 //short a, b;
5 //unsigned int c:2, d:1;
6 };
7 };
以上测试样例四输出结果:12
char+char*后的长度是8,union长度默认是1,
所以长度应该是9,但是结构体内最大变量的长度是4,不满足addr%4==0,所以结构需要进行调整。
(9+x)%4==0的最小长度是12
所以程序输出为12;
2 char ch, *ptr;
3 union {
4 short a, b;
5 //unsigned int c:2, d:1;
6 };
7 };
以上测试样例五输出答案:12
char====1
填充====3个空白字节
char*===4
union====1(内部short===2,a b共用2个字节),所以union长度是max(union,short)==2;
结构体内长度:1+3+4+2=10;
不满足结构体长度%4==0;
所以需要进行调整,最终为12
2 char ch, *ptr;
3 union {
4 short a, b;
5 unsigned int c:2, d:1;
6 };
7 };
以上测试样例六输出答案:12
这个分析同上。
只是需要说明的是位域在union中也是当成一个单独的变量,共用最长变量的内存单元,unsigned int长度为4。
2 //char ch, *ptr;
3 union {
4 short a, b;
5 unsigned int c:2, d:1;
6 };
7 };
以上测试样例七输出答案:4
同上
2 //char ch, *ptr;
3 union {
4 //short a, b;
5 unsigned int c:2, d:1;
6 };
7 };
以上测试样例八输出答案:4
同上
2 //char ch, *ptr;
3 union {
4 //short a, b;
5 //unsigned int c:2, d:1;
6 };
7 };
以上测试样例九输出答案:1
原则性的条款,union默认长度是byte长度===1