结构体和联合体(内存对齐)

结构体内存对齐:

1.为什么要进行内存对齐:

1)内存大小的基本单位是字节(byte),理论上来讲,可以从任意地址访问变量,但是实际上,cup 并非逐字节
读写内存,而是以 2,4,或 8 的倍数的字节块来读写内存,因此就会对基本数据类型的地址作出一些限制,即它的地址必须是 2,4 或 8 的倍数。那么就要求各种数据类型按照一定的规则在空间上排列,这就是对齐。
2)有些平台每次读都是从偶地址开始,如果一个 int 型(假设为 32 位系统)如果存放在偶地址开始的地方,那么一个读周期就可以读出这 32bit,而如果存放在奇地址开始的地方,就需要 2 个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该 32bit 数据。显然在读取效率上下降很多。
3)由于不同平台对齐方式可能不同,如此一来,同样的结构在不同的平台其大小可能不同,在无意识的情况下,互相发送的数据可能出现错乱,甚至引发严重的问题。

2.结构体在内存的存储方式:

要想理解内存对齐,首先必须得指导结构体在内存的存储方式。

struct Student
{
	 char s_id[8];
	 char s_name[8];
	 char s_sex[4];
	 int s_age;
};
 int main()
{
	 int a;
     Student stud;
	 cout << sizeof(Student) << endl;
	 return 0;
}

内存分布如图:
结构体和联合体(内存对齐)_第1张图片

3.内存对齐:

有了结构体的内存分布后,当然是要进行内存对齐了。

(1)首先是内存对齐的三个原则:

  1. 结构体变量的首地址,必须是结构体变量中的“最大基本数据类型成员所占字节数”的整数倍。
  2. 结构体变量中的每个成员相对于结构体首地址的偏移量,都是该成员基本数据类型所占字节数的整数倍
  3. 结构体变量的总大小,为结构体变量中 “最大基本数据类型成员所占字节数”的整数倍。

(2)内存对齐:

上边三个原则看上去很麻烦,其实挺简单的,下面上代码。

struct node
{
	 char cha;
	 int ia;
	 char chb;
};
 int main()
{
	 cout << sizeof(node) << endl;
	 return 0;
}

内存对齐后分布如图:
结构体和联合体(内存对齐)_第2张图片
这张图是假设从0地址开始,从0开始符合第一条原则;
第二条原则:ia是int类型,占4个字节,所以ia的开始地址是4;chb道理相同。
第三条原则:chb结束时,这个结构体共占了9个字节,但这不是实际的占有字节数,又第三条原则可以知道应该是最大成员的整数倍,最大是4,此时逻辑上占了9个,所以实际占12个字节。
我们可以测试一下:
结构体和联合体(内存对齐)_第3张图片

2.联合体:

联合体(union)与结构体(struct)有一些相似之处。但两者有本质上的不同。在结构体中,各成员有各自的内存空间。而在**联合体中,各成员共享同一段内存空间, 一个联合变量的长度等于各成员中最长的长度。**这里所谓的共享不是指把多个成员同时装入一个联合变量内, 而是指该联合变量可被赋予任一成员值,但每次只能赋一种值, 赋入新值则冲去旧值。
简而言之,就是联合体内所有成员共享同一段内存空间,用到哪个成员时,该空间就只取哪种成员。
联合体的字节数:(1)最大成员的字节数。(2)所以成员的整数倍

union UnData
{
    int st;
	char cs[2];
	 };
int main()
{
	union UnData x;
	cout << sizeof(x) << endl;
	return 0;
}

结构体和联合体(内存对齐)_第4张图片

常见的问题:

联合体和结构体的区别:
(1)结构体的各个成员会占用不同的内存,互相之间没有影响,而共用体的所有成员占用同一段内存,修改一个成员会影响其余所有成员。

(2)结构体占用的内存大于等于所有成员占用的内存的总和(成员之间可能会存在缝隙),共用体占用的内存等于最长的成员占用的内存。

(3)共用体使用了内存覆盖技术,同一时刻只能保存一个成员的值,如果对新的成员赋值,就会把原来成员的值覆盖掉。

你可能感兴趣的:(c语言)