C语言结构体中内存对齐的问题理解

 更新时间:2022年02月10日 10:56:25   作者:诚挚的乔治  
内存对齐”应该是编译器的“管辖范围”。编译器为程序中的每个“数据单元”安排在适当的位置上。但是C语言的一个特点就是太灵活,太强大,它允许你干预“内存对齐”。如果你想了解更加底层的秘密,“内存对齐”对你就不应该再模糊了

前言

学C的同学应该知道~

想精通C语言就不得不面对—指针与内存

续上次指针的进阶,这一章我来聊一聊C语言内存对齐的问题

学习结构体的你有没有注意过结构体向系统申请的内存为多少呢的😁

思考

#include<stdio.h>
typedef struct s1
{
	char a;
	char b;
	int c;
}s1;
typedef struct s2
{
	char a;
	int c;
	char b;
}s2;
int main()
{
 
	//内存对齐的现象
	printf("%d\n", sizeof(s1));
	printf("%d\n", sizeof(s2));
	return 0;
}

很显然这一段代码就是计算s1与s2向系统申请的内存大小

我:两个char类型各为一,再加上应该int类型的四,结果就是六

诚挚的乔治:你说的对,但不完全对,在结构体中会出现内存对齐的现象,不信?看结果

别慌,看到文章的最后,你(也许)就会恍然大悟

在结构体中,内存不是成员的大小之和

结构体在内存中开辟空间时内存对齐的规则

1.结构体中的第一个成员存放在这个结构体的零偏移处,故第一个成员char类型的的偏移量为零

2.从第二个成员开始,每个成员都要对齐到成员对齐数的整数倍

(对齐数--成员自身大小与默认对齐数的最小值的整数倍,如果自身大小是四,默认对齐数是八,最终的对齐数就是四的倍数),一般情况下默认对齐数就是八。

3.结构体的总大小必须是最大对齐数的整数倍 。

(最大对齐数就是每个成员对齐数中的最大值)

4.如果结构体中嵌套结构体的情况下,嵌套的结构体就对齐到自己成员对齐数的最大对齐数的整数倍处,结构体的总大小就是最大对齐数(含嵌套的结构体成员)的整数倍。

 下面其中的一个结构体进行分析:

 先向大家介绍一下本章的配角—offsetof

offsetof的返回值就是距离这个结构体(自定义类型)起始位置的值

参数就是结构体的名称和结构体成员的名称。

#include<stddef.h>
#include<stdio.h>
typedef struct s
{
	char a;
	int b;
	char c;
}s;
int main()
{
	//offsetof-是指偏移量
	printf("%d\n", offsetof(s,a));
	printf("%d\n", offsetof(s,b));
	printf("%d\n", offsetof(s,c));
	return 0;
}

char a; //因为char a是结构体第一个成员,所以偏移量就是零

int b;   //自身大小:  4    默认对齐数:8   对齐数:4的倍数即可,所以偏移量就是四

char c; // 自身大小: 1    默认对齐数:8   对齐数:1的倍数即可,所以偏移量就是八

又因为最终的结构体大小是成员最大对齐数的倍数,也就是四的倍数,所以最终的结构体的大小应该就是十二。

到这里是不是有一定的思路了,别急,再来一道试试吧

#include<stddef.h>
#include<stdio.h>
typedef struct s
{
	double a;
	char b;
	int  c;
}s;
int main()
{
	//offsetof-是指偏移量
	printf("%d\n", offsetof(s,a));
	printf("%d\n", offsetof(s,b));
	printf("%d\n", offsetof(s,c));
	printf("%d", sizeof(s));
	return 0;
}

结果如下:

是不是跟你想的一样呢?

同样的,用一样的方法进行解释

double a;     //因为double a是结构体第一个成员,所以偏移量就是零

char b;     //自身大小:1    默认对齐数:8  对齐数:1的倍数即可,所以偏移量就是八

int  c;        //自身大小:4    默认对齐数:8   对齐数:4的倍数即可,所以偏移量就是十二

最终结构体的大小就是四的整数倍十六

下面给应该结构体嵌套结构体的例子

#include<stdio.h>
#include<stddef.h>
typedef struct s1
{
	char i;
	char j;
	int k;
}s1;
typedef struct s2
{
	char a;
	int c;
	s1;
}s2;
int main()
{
 
	printf("%d\n", offsetof(s2, a));
	printf("%d\n", offsetof(s2, c));
	printf("%d", sizeof(s2));
	return 0;
}

我相信此时的你一定会计算结构体想系统申请的大小,以及内存对齐是咋回事

其实,内存对齐也就那么回事儿~

为什么存在内存对齐

知道怎样计算后,你是否和我一样思考

为什么内存的申请不能想main函数中的内存申请一样,要多少就申请相应大小的空间,这样既省内存,也不用考虑这么多。

1.平台的原因

所谓平台原因就是与硬件有关,硬件不能访问内存中的每一个空间,换句话说,就是按一定的规律进行访问,这样内存对齐就起到了很好的作用

2.性能的原因

数据结构(尤其是栈),应该尽可能的在自然边界上对齐

因为我们的CPU访问空间,就是一次性按四个字节的空间来访问,内存对齐在一定的时候避免了访问一次的空间进行了二次访问

如下访问应该int类型内存对齐后只需要访问一次

总的来说内存对齐就是拿空间换取时间

当然,我们可以实现内存对齐之上,也可以进行省一定空间

就想博客开头一道题,一模一样的代码,最终的结构体的大小却不一样,这种就是优化版的结构体

这里给一个小的技巧,就是把空间小的成员尽量放在一起

到此这篇关于C语言结构体中内存对齐的问题理解的文章就介绍到这了,更多相关C语言 内存对齐内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • c++中的自增/自减操作方式

    c++中的自增/自减操作方式

    这篇文章主要介绍了C++中的自增和自减运算符,包括前缀和后缀形式,并通过一个具体的例子解释了自增/自减表达式的值与函数参数传递的关系,文章指出,自增/自减表达式的值是在表达式求值时确定的,而不是在自增/自减运算后
    2025-03-03
  • 推箱子游戏C语言实现代码

    推箱子游戏C语言实现代码

    这篇文章主要为大家详细介绍了推箱子游戏C语言实现代码,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-12-12
  • C++ string字符串的使用和简单模拟实现

    C++ string字符串的使用和简单模拟实现

    C语言中,字符串是以'\0'结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数,但是这些库函数和字符串是分离的,本文给大家介绍了C++ string字符串的使用和简单模拟实现,感兴趣的朋友可以参考下
    2024-06-06
  • C语言详细讲解循环语句的妙用

    C语言详细讲解循环语句的妙用

    C语言循环控制语句是一个基于C语言的编程语句,该语句主要有while循环语句、do-while循环语句和for循环语句来实现循环结构,在循环过程中还有关键字break、continue、do、break控制中断继续与结束等操作
    2022-04-04
  • c语言全局变量和局部变量问题及解决汇总

    c语言全局变量和局部变量问题及解决汇总

    局部变量能否和全局变量重名,如何引用一个已经定义过的全局变量,全局变量可不可以定义在可被多个.C文件包含的头文件中?为什么?,接下来为您一一介绍
    2013-01-01
  • C语言中字母大小写转化简单示例

    C语言中字母大小写转化简单示例

    在C语言中,有时候我们遇到这样的考题,将c语言大写字母转化为小写字母,下面这篇文章主要给大家介绍了关于C语言中字母大小写转化的相关资料,文中介绍的非常详细,需要的朋友可以参考下
    2022-11-11
  • C语言 设计模式之访问者模式

    C语言 设计模式之访问者模式

    这篇文章主要介绍了C语言 设计模式之访问者模式的相关资料,需要的朋友可以参考下
    2017-01-01
  • 探讨:用两个栈实现一个队列(我作为面试官的小结)

    探讨:用两个栈实现一个队列(我作为面试官的小结)

    作为面试官的我,经常拿这道用两个栈实现一个队列的面试题来考面试者,通过对面试者的表现和反应,有一些统计和感受,在此做个小结
    2013-05-05
  • C++实现中值滤波的示例代码

    C++实现中值滤波的示例代码

    本文主要介绍了C++实现中值滤波的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-05-05
  • Windows系统vscode安装与配置G++、Cmake的图文步骤

    Windows系统vscode安装与配置G++、Cmake的图文步骤

    本文主要介绍了Windows系统vscode安装与配置G++、Cmake的步骤,文中通过图文示例介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2025-04-04

最新评论