c语言在计算自定义的结构体的内存时常常要考虑到结构体内存对齐,那么什么是结构体内存对齐呢?
结构体内存对齐规则
1. 第一个成员在与结构体变量偏移量为0的地址处。
2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
VS中默认的值为8
3. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍。
4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整
体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。
例如下列代码
struct s1
{
char c1; //默认对齐数:8 vs 变量C1所占字节数:1 ——>对齐数:1
int i; //默认对齐数:8 vs 变量i所占字节数:4 ——>对齐数:4
char c2; //默认对齐数:8 vs 变量c2所占字节数:1 ——>对齐数:1
}
//结构体所占大小为 12个字节
//结构体的最大对齐数:4
在内存中表示为:
因为在结构体s1中,第二个变量i的对齐数是4,所以变量i的存储的地址必须为四的倍数,导致第一个变量c1占完第一个字节后,后面三个字节没有被利用,而是到第四个字节处存储第二个变量i。
当我们调换变量顺序后,结构体占用内存的大小可能会发生变化,例如:
struct s2
{
char c1; //默认对齐数:8 vs 变量C1所占字节数:1 ——>对齐数:1
char c2; //默认对齐数:8 vs 变量C2所占字节数:1 ——>对齐数:1
int i; //默认对齐数:8 vs 变量i所占字节数:4 ——>对齐数:4
}
//结构体所占大小为 8个字节
//结构体最大对齐数:4
在内存中表示为:
因为第一个变量c1和第二个变量c2的对齐数都是1,所以第一个字节的位置和第二个字节的位置都是1的倍数,因此第一个字节和第二个字节用来存储第一个变量c1和第二个变量c2,而第三个变量i的对齐数是4,所以在第四个字节(4的倍数)的位置存储i。
同理,对于以下代码:
struct s3
{
double d; //默认对齐数:8 vs 变量d所占字节数:8 ——>对齐数:8
char c; //默认对齐数:8 vs 变量c所占字节数:1 ——>对齐数:1
int i; //默认对齐数:8 vs 变量i所占字节数:4 ——>对齐数:4
}
//结构体大小:16
//结构体最大对齐数:8
而对于嵌套的结构体来说:
struct s4
{
char c1; //默认对齐数:8 vs 变量c1所占字节数:1 ——>对齐数:1
struct S3 s3; //默认对齐数:8 vs 变量s3所占字节数:8 ——>对齐数:8
double d; //默认对齐数:8 vs 变量d所占字节数:8 ——>对齐数:8
}
//结构体大小:32
//结构体最大对齐数:8
因为变量s3的对齐数是8,所以在第一个字节被变量c1使用后,跳过七个字节,在第八个字节的位置(8的倍数)存储s3。
以上就是关于c语言中结构体内存对齐的知识了,那么为什么结构体要内存对齐了,有以下三个方面的原因:
-
不是所有的硬件平台都能访问任意地址上的数据;
-
某些硬件平台只能只在某些地址访问某些特定类型的数据,否则抛出硬件异常,及遇到未对齐的边界直接就不进行读取数据了。
-
为了代码的可移植性,和提升CPU访问内存的效率,所以结构体一定要内存对齐。
结构体的内存对齐本质上来说是 以空间换时间 来提高结构体的高效性。