内存对齐与结构体大小

(一)内存对齐

(1)什么是内存对齐?

(2)为什么要有内存对齐?

(3)如何内存对齐?

(二)结构体大小计算

例(1)

例(2)

例(3)


(一)内存对齐

(1)什么是内存对齐?

通过牺牲空间,来提升访问速度。(拿空间换时间)

        举例:环境为32位的系统,假设在内存中只能从4的整数倍处的地址读取数据,地址空间如下图,依次插入int a = 10(大小是4字节),char c = ‘s’ (大小是1字节),int b = 1(大小是4字节)。按照假设的读取规则,三个变量应该按下图所插入。在这个过程中,因为需要遵守读取数据的规则,所以需要牺牲掉一些空间,这就是内存对齐。

(2)为什么要有内存对齐?

        本质是因为硬件平台的限制,导致数据读取可能会出现低效率问题,通过“浪费”某些空间的方式,来达到快速读取目标数据的目的。

        举例:环境依然是32位,假设在内存中只能从4的整数倍处的地址读取数据,依次插入char a =’s’,int b = 10。但我们这次连续插入,不考虑内存对齐。

        在我们读取数据时,因为在内存中只能从4的整数倍处的地址读取数据,地址到1时,char类型读取完毕,接下来要读取出地址在1到4之间的那部分int类型的数据,然后保存,然后继续从地址4开始读取剩下那部分的int类型数据保存,之后再将两部分int类型的数据合并才能得到完整的int型数据。如下图所示:

(3)如何内存对齐?

首先给出内存对齐的规则(也是计算结构体大小的根据):

 1.第一个成员在与结构体变量偏移量为0的地址处。

 2.其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处

    对齐数=编译器默认的对齐数 与 该成员大小的较小值

    VS默认对齐数为8

 3.结构体总大小为最大对齐数(每个成员变量都有一个对齐数,所有成员变量中最大的对齐数就是结构体的最大对齐数)的整数倍

 4.如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构的对齐数)的整数倍

(二)结构体大小计算

例(1)

        求如下代码结构体A的总大小:(以下三个例子的答案均是在win10系统下的VS2019中验证的)

#include <stdio.h>

struct A{
	char a;
	int b;
};

int main(){
    printf("A的大小:%d\n",sizeof(struct A));//结果是 8
}

         a的空间:第一个成员变量需要在偏移量为0的地址处,则a的空间是0到1;

        b的空间:计算第二个成员变量地址时,根据规则2,首先要计算对齐数,VS默认对齐数是8,该成员大小是4,4小于8,则对齐数是4,地址增加到4时,刚好可以整除对齐数,所以第二个成员所占空间是地址4到8之间。

        计算结构体总大小,先求出最大对齐数,所有成员变量中最大对齐数是4,当前结构体所占的空间为8(地址末尾是8,起始是0),8是最大对齐数的整数倍,则总大小是8。图解如下:

例(2)

        求如下代码结构体B的总大小:

#include <stdio.h>

struct B {
	char a;
	int b;
	double c;
};

int main() {
	printf("B的大小:%d\n", sizeof(struct B));//结果是 16
}

        有了上述步骤,接下来不再赘述,直接进行计算。

        a的空间:地址0到1处。计算b时,对齐数是4,所占空间是地址4到8处。

        c的空间:对齐数是8,所占空间是地址8到16处。

         计算结构体总大小:整个结构体最大对齐数是8,结构体此时大小是16,恰好是8的倍数。结构体总大小是16。图解如下:

例(3)

        求如下代码结构体C的总大小:

#include <stdio.h>

struct B {
	char a;
	int b;
	double c;
};

struct C {
	char m;
	double n;
	struct B b;
};

int main() {
	printf("C的大小:%d\n", sizeof(struct C));//结果是 32
}

        

        这个例子是运用规则四,计算嵌套结构体。

        m的空间:地址0到1处。b的空间:对齐数是8,所占空间是地址8到16处。结构体B所占空间:对齐数16,多占空间是16到32处。

        计算结构体总大小::整个结构体C最大对齐数是8(有没有好奇为什莫不是16),结构体此时大小是32,32是8的倍数,所以总大小是32。图解如下:

        注:在例3中,结构体C的最大对齐数是8,而不是16。因为内部嵌套的结构体B的对齐数是它内部所有成员的对齐数中最大的一个,也就是8。

        以上几个例子都恰好直接计算出了总大小,但大多是并不是如此巧合。例如当结构体占了30个空间,最大对齐数是8时,30不是8的倍数,所以需要增加空间到32,所以该结构体总大小是32。

(三)修改默认对其数

#pragma pack (n)//n是要设置的默认对齐数
  • 14
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
在计算结构大小时,需要考虑到内存对齐的问题。内存对齐是为了优化内存访问速度而进行的一种技术,它要求不同数据类型的变量在内存中的存储地址要按照一定规则进行对齐。具来说,每个数据类型都有一个对齐值,即该数据类型变量在内存中存储的起始地址必须是该对齐值的倍数。 在C语言中,可以使用`sizeof`运算符来计算结构大小,但是这个大小可能会受到内存对齐的影响。为了确保计算出的大小是考虑了内存对齐的,我们可以使用`__alignof__`关键字来获取每个成员变量的对齐值,并手动进行对齐计算。 下面是一个示例代码,演示如何使用内存对齐计算结构大小: ```c #include <stdio.h> struct my_struct { char c; int i; double d; }; int main() { struct my_struct s; size_t size = sizeof(s); size_t align_c = __alignof__(s.c); size_t align_i = __alignof__(s.i); size_t align_d = __alignof__(s.d); size_t align = align_c > align_i ? align_c : align_i; align = align > align_d ? align : align_d; size_t padding_c = align - sizeof(s.c) % align; size_t padding_i = align - sizeof(s.i) % align; size_t padding_d = align - sizeof(s.d) % align; size_t padding = padding_c + padding_i + padding_d; size += padding; printf("Size of my_struct: %zu\n", size); return 0; } ``` 在上面的示例代码中,我们首先定义了一个`my_struct`结构,其中包含一个`char`类型的成员变量`c`、一个`int`类型的成员变量`i`和一个`double`类型的成员变量`d`。然后我们使用`sizeof`运算符计算出结构大小,并使用`__alignof__`关键字获取每个成员变量的对齐值。接下来,我们计算出结构需要进行的对齐和填充,最后将填充的大小加入到结构大小中,输出计算出的结构大小。 需要注意的是,对齐值可能会因为编译器和操作系统的不同而有所差异,因此在实际应用中需要谨慎处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值