] 本帖最后由 Yuhailong 于 2020-5-13 20:33 编辑 [/i]
[md]从别处搬来的,给大家分享一下
一、存储变量时地址要求对齐,编译器在编译程序时会遵循两条原则:
(1)结构体变量中成员的偏移量必须是成员大小的整数倍(0被认为是任何数的整数倍)
(2)结构体大小必须是所有成员大小的整数倍,也即所有成员大小的公倍数。
二、 对于嵌套的结构体,需要将其展开。对结构体求sizeof时,上述两种原则变为:
(1)展开后的结构体的第一个成员的偏移量应当是被展开的结构体中最大的成员的整数倍。
(2)结构体大小必须是所有成员大小的整数倍,这里所有成员计算的是展开后的成员,而不是将嵌套的结构体当做一个整体。
为什么?
但是编译器为什么要这么做,以下是我的理解。
为什么要对齐?
因为在32位操作系统(虽然64位操作系统,但是为了保证兼容性,编程仍然主要考量32位)中,数据总线是32位,地址总线是32位。
地址总线是32位,意味着寻址空间是按4递增的;数据总线32位意味着一次可读写4byte。
考虑这样一个结构体
struct stu1
{
char c1;
int i;
char c2;
}
不对齐就意味着,当我们执行stu1.i 时,需要读取内存两次。而对齐后,就只需要读取一次,众所周知,I/O操作是很耗时的,编译器做出对齐的选择也就好理解。
为什么不完全按照4字节对齐的?
既然对齐可以避免上述的问题,为什么不将所有存储小于4byte的数据类型(char, short等)统统按4byte对齐呢?
考虑这样一个结构体
struct stu2
{
char c;
short s;
int i;
double d;
}
为什么编译器采用B方案,而不采用A方案?
还是因为32数据线一次读取4个字节,
采用方案A,读取stu2.c,或者stu2.s,要一次读取4个byte,再舍弃无关内存的数据。
采用方案B,读取stu2.c,或者stu2.s,也是要一次读取4个byte,再舍弃无关内存中的数据。
同样的I/O操作,相比之下,明显方案B更节省内存。
补充: 如上图中,所示8字节的数据类型,比如double, long long,必须要读取两次内存。 |