服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C/C++ - C语言热门考点结构体与内存对齐详解

C语言热门考点结构体与内存对齐详解

2022-02-13 16:12高邮吴少 C/C++

在掌握基本的结构体使用后,我们在面试和大型比赛中常常会遇到一个热门考点:结构体内存对齐,也就是计算结构体大小。接下来请跟着笔者一起来学习这块知识点吧

 

一、引例

到底什么是结构体内存对齐,我们用一段代码来介绍一下

struct S1
{
	char c1;//1字节
	int a;//4字节
	char c2;//1字节
};
int main()
{
	printf("%d
", sizeof(struct S1));
	//这里打印12
}

先来解释S1,结构体S1中有2个char类型,1个int类型。那按道理应该是占2*1+4=6个字节啊,为什么打印的是12呢?到这里,我们必须要来了解一下结构体内存对齐的规则:

 

1.结构体的第一个成员永远放在结构体起始位置偏移量为0的位置

对于偏移量你可以这样理解:数组下标为0的相对它自己偏移量为0,下标为1的相对下标为0的偏移量为1…
举例说明:

C语言热门考点结构体与内存对齐详解

S1第一个成员是c1,它会被放在结构体起始位置偏移量为0的位置,如下图红色部分

C语言热门考点结构体与内存对齐详解

 

2.从第二个成员开始,总是放在偏移量为一个对齐数的整数处,对齐数=编译器默认的对齐数和变量自身大小的较小值

对齐数=min(编译器默认的对齐数,变量自身大小)
Linux-没有对齐数,VS下对齐数默认为8

我们仍以S1这个结构体进行举例,结构体第二个成员是int类型的a,占4个字节,笔者VS环境下默认对齐数是8,取两者较小值是4,那a应该放到偏移量为4的倍数上

C语言热门考点结构体与内存对齐详解

放到4的倍数上也就说可以放在偏移量为4这里,偏移量为1,2,3的这3个空间就白白被浪费了。而a是int型占4个字节,所以会一直占用到偏移量为7的位置。

接下来是结构体的第三个成员,char类型的c2,c2占1个字节,VS环境下默认对齐数是8,取较小值为1,也就是说只要是1的倍数的偏移量都可以放,我们紧接着放在a后面,也就是偏移量8的位置

C语言热门考点结构体与内存对齐详解

那到这里结构体3个成员都用完了啊,只有8个啊,为什么打印是12呢?这里就要涉及结构体内存对齐的第3个规则

 

3.结构体的总大小必须是各个成员的对齐数中最大的那个对齐数的整数倍

我们由前面讲解知道结构体三个成员c1,a,c2对齐数分别为1,4,1这三个中最大对齐数是4,总大小要为4的整数倍,那这时候肯定有小伙伴会问:我们现在不是对齐到8了嘛,8不是4的倍数吗?注意!这里说的是空间总大小,而8是所谓的偏移量,偏移量是从0开始算的,到8已经有9个空间了,所以我们这里空间要到12,也就是偏移量到11

C语言热门考点结构体与内存对齐详解

(后面加上的三个空间用不到,但是由于规定还是算在结构体总空间内)

 

二、小试牛刀

我们再来看一道类似的题目

代码如下(示例):

struct S2
{
	char c1;//1字节
	char c2;//1字节
	int a;//4字节
};
int main()
{
	printf("%d
", sizeof(struct S2));
	//这里打印8
}

首先第一个结构体成员是char类型的c1,由规则1,它会直接被放在偏移量为0的位置
(图示灰色部分)

C语言热门考点结构体与内存对齐详解

第二个成员是char类型的c2,占1字节,VS下默认对齐数是8,取较小值是1,只要放在偏移量为1的倍数上即可(任意位置),紧跟着0,放在偏移量为1处(图示红色部分)

C语言热门考点结构体与内存对齐详解

最后一个成员int类型的a,占4个字节,VS环境下默认对齐数是8,取较小者4,放在偏移量为4的整数倍处,也就是4这里,然后由于int占4个字节所以一直占用到偏移量7处

C语言热门考点结构体与内存对齐详解

再来看看规则3,结构体的总大小必须是各个成员的对齐数中最大的那个对齐数的整数倍,也就是4的倍数,我们现在正好是占8个空间,8正好是4的倍数,所以就不用再往下浪费空间了,打印出8

 

三、嵌套结构体的特殊情况

代码如下(示例):

struct S3
{
	double d;//double占8字节,默认对齐数8,取较小值,对齐数8
	char c;//对齐数1
	int i;//对齐数4
};
struct S4
{
	char c1;
	struct S3 s3;
	double d;
};
int main()
{
	printf("%d
", sizeof(struct S4));
}

关于结构体S3我们可以采用和前面S1、S2一样的方法计算出来是占16个字节空间,我们这里重点讨论S4,对S3有兴趣的小伙伴可自行求解。

S4中的第一个成员c1,按规则1直接放在偏移量为0处,第二个成员s3怎么办呢?这里涉及结构体内存对齐的第四个规则:

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

s3这个结构体三个成员最大对齐数是8,也就是要对齐到偏移量为8的倍数处,然后s3是占16个字节,所以一直占到偏移量23处(s3结构体对齐数是本身s3结构体三个成员中最大对齐数)

ps:在VS环境中,嵌套结构体的最大对齐数超过8,仍然用8做最大对齐数(比默认对齐数大了,取较小值就取默认对齐数了)

C语言热门考点结构体与内存对齐详解

S4最后一个成员double类型的d占8字节,默认对齐数8,对齐数取8,然后放在偏移量为对齐数的整数倍处,正好往下放在24处,本身占8字节所以占到31

C语言热门考点结构体与内存对齐详解

偏移量0-31共占32字节,S4中的成员c1,s3,d对齐数分别为1,8,8所以最大对齐数是8,32恰是8的倍数,所以这里不用再浪费空间来满足 “结构体的总大小必须是各个成员的对齐数中最大的那个对齐数的整数倍”这个规则,结构体总大小就是32

 

四、关于为什么存在内存对齐

 

1.平台原因(移植原因):

不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定的类型的数据,否则抛出硬件异常

 

2.性能原因:

数据结构(尤其是栈),应尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅仅需要1次
总体来说:结构体的内存对齐是用空间换时间

 

总结

本文介绍了结构体内存对齐的四大规则,并举例说明了如何进行方法的操作,对于其中特殊的嵌套结构体内存对齐也进行了相应讲解,希望读者在学习完本文后能对结构体内存对齐有一个系统的认识。祝读者学业有成!

更多关于C语言结构体与内存对齐的资料请关注服务器之家其它相关文章!

原文链接:https://blog.csdn.net/m0_57180439/article/details/120471488

延伸 · 阅读

精彩推荐
  • C/C++c/c++内存分配大小实例讲解

    c/c++内存分配大小实例讲解

    在本篇文章里小编给大家整理了一篇关于c/c++内存分配大小实例讲解内容,有需要的朋友们可以跟着学习参考下。...

    jihite5172022-02-22
  • C/C++C语言main函数的三种形式实例详解

    C语言main函数的三种形式实例详解

    这篇文章主要介绍了 C语言main函数的三种形式实例详解的相关资料,需要的朋友可以参考下...

    ieearth6912021-05-16
  • C/C++使用C++制作简单的web服务器(续)

    使用C++制作简单的web服务器(续)

    本文承接上文《使用C++制作简单的web服务器》,把web服务器做的功能稍微强大些,主要增加的功能是从文件中读取网页并返回给客户端,而不是把网页代码...

    C++教程网5492021-02-22
  • C/C++关于C语言中E-R图的详解

    关于C语言中E-R图的详解

    今天小编就为大家分享一篇关于关于C语言中E-R图的详解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看...

    Struggler095962021-07-12
  • C/C++C语言实现双人五子棋游戏

    C语言实现双人五子棋游戏

    这篇文章主要为大家详细介绍了C语言实现双人五子棋游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    两片空白7312021-11-12
  • C/C++深入C++拷贝构造函数的总结详解

    深入C++拷贝构造函数的总结详解

    本篇文章是对C++中拷贝构造函数进行了总结与介绍。需要的朋友参考下...

    C++教程网5182020-11-30
  • C/C++OpenCV实现拼接图像的简单方法

    OpenCV实现拼接图像的简单方法

    这篇文章主要为大家详细介绍了OpenCV实现拼接图像的简单方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    iteye_183805102021-07-29
  • C/C++c/c++实现获取域名的IP地址

    c/c++实现获取域名的IP地址

    本文给大家汇总介绍了使用c/c++实现获取域名的IP地址的几种方法以及这些方法的核心函数gethostbyname的详细用法,非常的实用,有需要的小伙伴可以参考下...

    C++教程网10262021-03-16