forked from hengqiali/AwesomeCpp
-
Notifications
You must be signed in to change notification settings - Fork 0
/
结构体内存对齐
110 lines (90 loc) · 4.84 KB
/
结构体内存对齐
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#include <iostream>
using namespace std;
/****************** struct --内存对齐 **********************/
/*
内存对齐主要遵循以下原则:
1. 对于结构体的各个成员,第一个成员的偏移量是0,排列在后面的成员其当前偏移量必须是当前成员类型的整数倍
2. 结构体内所有数据成员各自内存对齐后,结构体本身还要进行一次内存对齐,保证整个结构体占用内存大小是结构体内最大数据成员的最小整数倍
3. 如程序中有#pragma pack(n)预编译指令,则所有成员对齐以n字节为准(即偏移量是n的整数倍),不再考虑当前类型以及最大结构体内类型
其实这里有点不严谨,编译器在编译的时候是可以指定对齐大小的,实际使用的有效对齐其实是取指定大小和自身大小的最小值,一般默认的对齐大小是4。
再回到上面的例子,如果默认的对齐大小是4,结构体a的其实地址为0x0000,能够被最宽的数据成员大小(这里是int, 大小为4,有效对齐大小也是4)整除,
故char a的从0x0000开始存放占用一个字节即0x0000~0x0001,然后是int b,其大小为4,故要满足2,需要从0x0004开始,所以在char a后填充三个字节,
因此a对齐后占用的空间是0x0000~0x0003,b占用的空间是0x0004~0x0007, 然后是short c其大小是2,故从0x0008开始占用两个字节,即0x0008~0x0009。
此时整个结构体占用的空间是0x0000~0x0009, 占用10个字节,10%4 != 0,
不满足第三个原则,所以需要在后面补充一个字节,即最后内存对齐后占用的空间是0x0000~0x000B,一共12个字节。
https://levphy.github.io/2017/03/23/memory-alignment.html
https://www.zhihu.com/question/27862634
https://www.cnblogs.com/Miranda-lym/p/5197805.html struct\union\class都一样
那么为什么需要内存对齐呢?
---》结构体的对齐明明浪费了更多的空间,但是却提高了内存系统性能!
最重要的考虑是提高内存系统性能。为了简化电路设计,实际上计算机会将字节组成一个大点的格子,32 位机器,就以 4 个字节作为一个格子。
64 位机器,就以 8 字节作为一个格子。在 64 位机上,就算读取 1 字节的数值,也需要读取整个 8 字节的格子。例如,假设计算机总是从内存中取8个字节,
如果一个double数据的地址对齐成8的倍数,那么一个内存操作就可以读或者写,但是如果这个double数据的地址没有对齐,
数据就可能被放在两个8字节块中,那么我们可能需要执行两次内存访问,才能读写完成。显然在这样的情况下,是低效的。所以需要字节对齐来提高内存系统性能。
在有些处理器中,如果需要未对齐的数据,可能不能够正确工作甚至crash
*/
struct{
char a; //0->1(7),1还没占
double b; //偏移的是0->7总共8个字节是8的整数倍,占8->16,16还没占
short c; //16->18,18还没占 总共0-17
} test1;
struct{
char a; //0->2,2还没占
int b; //4->8 8还没占
short c; //8->10(12),10还没占,补充到0-11
} test2;
struct{
char a; //0->1
short c; //2->4
int b; //4->8
} test3;
struct{
int b; //0->4
char a; //4->5
short c; //跳过0-5,6->8,8还没占
} test4;
struct{
int number; //0->4
union UBffer
{
char buffer[13]; //4->17 17还没占
int number;
}ubuf;
int aa; //17开始的话,偏移了0-16 = 17不行,得偏移20个字节,所以0->20 20还没占,所以当前占20->24
double dou; //24->32 0--31
}test5;
struct {
short number; // 0->8
union UBffer
{
char buffer[13]; //相当于偏移了0-7,8没占,8->21,21还没占,但是为了内存补齐规则3,必须得是8->24,24没占
double number;
}ubuf;
}test6;
struct {
short number; // 0->8
union UBffer
{
char buffer[13]; //相当于偏移了0-7,8没占,8->21,21还没占,但是为了内存补齐规则3,必须得是8->24,24没占
double number;
}ubuf;
char a; //24->32
double b; //32->40 所以最后是0-39 占用40个B
}test7;
int main()
{
cout << "sizeof(char) = " << sizeof(char) << endl;
cout << "sizeof(short) = " << sizeof(short) << endl;
cout << "sizeof(int) = " << sizeof(int) << endl;
cout << "sizeof(float) = " << sizeof(float) << endl;
cout << "sizeof(long) = " << sizeof(long) << endl;
cout << "sizeof(double) = " << sizeof(double) << endl;
cout << sizeof(test1) << endl; // 24
cout << sizeof(test2) << endl; // 12
cout << sizeof(test3) << endl; // 8
cout << sizeof(test4) << endl; // 8
cout << sizeof(test5) << endl; // 32
cout << sizeof(test6) << endl; // 24
cout << sizeof(test7) << endl; // 40
return 0;
}