C语言结构体字节对齐的实现深入分析

 更新时间:2022年10月19日 15:06:27   作者:是星星鸭  
这篇文章主要介绍了C语言结构体字节对齐的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

前言

本教程可能会用到一点汇编的知识,看不懂没关系,知道是那个意思就行了。使用的工具是vs2010。

一、什么是字节对齐

字节对齐是字节按照一定规则在空间上排列。

现代计算机中内存空间都是按照byte划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特 定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。

在我们之前写程序的时候可能会发现有的时候你定义的变量是一个字节,但是他在内存中依然按照四个字节给你存储,因为在32为系统中,4字节对齐执行效率是最快的。这就是一种牺牲内存换取性能的方案。

举个栗子

我们知道,全局变量在在内存中是有一个固定的地址的,如果不重新编译的话,这个地址是不会改变的。所以我们拿全局变量举例。

如下,我们定义两个全局变量:

一个是char(单字节)的一个是int(4字节的)

然后我们在main函数中给他们赋值,如下:

然后断点、F7编译、F5调试、ALT+8转到反汇编:

可以看到他们之间差值为4字节

再次测试,如下:

反汇编:

差值为2。

因为字节对齐的原因,int类型的起始地址必须是4的整数倍,short类型的起始地址也必须是2的倍数,当然char就没有那么约束了,因为它只是一个字节的。并不是说char类型的变量与int变量的差值是因为int类型占了四个字节所以差值才为4 。

再做测试,如下:

打乱顺序。查看反汇编:

总结如图。

再次强掉、因为字节对齐的原因,变量的起始地址必须是变量字节大小的整数倍

二、结构体字节对齐

结构体中成员的存储方式也是按照上面的字节对齐方式进行存储的。不过有一点区别:结构体的起始地址是其最宽数据类型的整数倍(千万不要死记:结构体宽度就是最宽数据类型的整数倍,因为这样容易忘,下面我来和大家分析为什么是这样,知道为什么才能记得更久)。

举个栗子

结果:

我们分析一下:

int 4字节、char 1字节、double 8字节,按理说应该是13字节对吧。

分析如下:

int类型占了4个字节,这个时候char类型因为字节对齐的原因、他的起始地址是1的整数倍,所以它可以挨着int类型。但是double,他是8个字节的,由于字节对齐的原因、他的起始地址必须是8的倍数,所以他和char类型之间会差3。但是int、char、double他们是一个结构体的成员,不是分开存储的。所以char和double之间空的三个字节因为字节对齐的原因必须补齐。

再来:

可以先猜测一下结果。

结果如下:

这里大家可以试着推测,只需要记住因为字节对齐的原因,char起始地址必须是1的整数倍、int必须是4的整数倍等等。

三、#pragma pack()的使用

当对内存要求较高的时候,我们不得不抛弃性能。这个时候可以通过#pragma pack(n)来强制结构体成员的对齐方式

#pragma pack(1)

struct st_info

{

char a;

int b;

};

#pragma pack()

<1> #pragma pack(n)中的n用来设定变量以n字节的方式对齐,可以设定的值包括:1、2、4、8,VC编译器默认是8。

<2> 若需要强制取消字节对齐方式,则可使用#pragma pak()取消。

举个栗子:

示例代码:

#include <stdio.h>
#include <Windows.h>
#pragma pack(2)
struct stinfo
{
	char   t;
	int    x;
	char   y;
	double m;
};
#pragma pack()
int main()
{
	printf("%d\n", sizeof(stinfo));
 
	while(1);
	return 0;
}

如下:

这里我们让结构体以2字节的方式对齐,所以猜想:

char t因为字节对齐的原因起始地址应该是2的整数倍,但是他是首地址,不用管。

t = 1个字节。

int x类型因为pack(2)的原因,起始地址应该是2的整数倍,所以它和chart的差值应该为2,也就是补1个字节。

t+1+x = 6个字节

到这里,t和x已经占有6个字节。

char y因为pack(2)的原因,他的起始地址应该是2的整数倍,但是上面六个字节正好是2的倍数。

t+1+x+y = 7个字节

到这里t、x、y三个成员已经占有7个字节。

double m因为pack(2)的原因,起始地址不得不是2的整数倍,但是上面7个字节显然不对,所以因为字节对齐的原因,上面t、x、y三个成员需要再补一个字节,这个时候加上double的8个字节。

t+1+x+y+1+8 = 16个字节

结果如下:

猜想正确。

如果我们不强制字节对齐的话:

char t一个字节

int x起始地址必须是4的整数倍,所以t必须补3个字节

x+t+3 = 8个字节

char y一个字节

x+t+3+y = 9个字节

double m起始地址必须是8的倍数,所以x+t+y需要补7个字节。

x+t+3+y+7+8 = 24个字节

结果如下:

对于pack(1)、pack(4)、pack(8)大家自己尝试下吧。

总结

通过上面的讲解,想必大家应该知道结构体的字节数为什么是成员中最宽数据类型字节数的整数倍了的,但是还是那句话,不要死记这一点,明白为什么才是重点、才能记得更久。

因为字节对齐的原因、结构体中成员的起始地址、假设该成员是int类型,那么它的起始地址必须是4的整数倍,如果是double类型,那么他的起始地址必须是8的整数倍。当然也可以强制他们的起始地址是一个固定数字(1、2、4、8)的整数倍。通过#pragma pack(n)即可。

到此这篇关于C语言结构体字节对齐的实现深入分析的文章就介绍到这了,更多相关C语言结构体字节对齐内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • C++ Boost Fusion创建异构容器详解

    C++ Boost Fusion创建异构容器详解

    Boost.Fusion 使创建异构容器成为可能。例如,您可以创建一个向量,其第一个元素是 int,第二个元素是字符串。此外,Boost.Fusion 提供了处理异构容器的算法。您可以将 Boost.Fusion 视为异构容器的标准库
    2022-11-11
  • Qt编写自定义控件实现抽奖转盘

    Qt编写自定义控件实现抽奖转盘

    这篇文章主要为大家详细介绍了Qt编写自定义控件实现抽奖转盘,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-06-06
  • C++实现支持泛型的LFU详解

    C++实现支持泛型的LFU详解

    这篇文章主要给大家介绍了关于C++实现LFU的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用Redis具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2021-09-09
  • C++算术运算符与类型转换

    C++算术运算符与类型转换

    这篇文章主要介绍了C++算术运算符与类型转换,C++当中提供5种基础的算术运算符,分别是加法、减法、乘法、除法和取模。下main我们就一起来看看下面文章得具体举例与说明,需要的朋友可以参考一下,希望对你有所帮助
    2021-11-11
  • C++数据结构之AVL树的实现

    C++数据结构之AVL树的实现

    AVL树是高度平衡的而二叉树,它的特点是AVL树中任何节点的两个子树的高度最大差别为1,本文主要给大家介绍了C++如何实现AVL树,需要的朋友可以参考下
    2022-06-06
  • OpenCV实现马赛克和毛玻璃滤镜效果

    OpenCV实现马赛克和毛玻璃滤镜效果

    这篇文章主要为大家详细介绍了OpenCV实现马赛克和毛玻璃滤镜效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-01-01
  • c语言实现单链表算法示例分享

    c语言实现单链表算法示例分享

    这篇文章主要介绍了c语言实现单链表算法示例,需要的朋友可以参考下
    2014-02-02
  • C语言简明讲解快速排序的应用

    C语言简明讲解快速排序的应用

    快速排序由于排序效率在同为O(N*logN)的几种排序方法中效率较高,因此经常被采用,再加上快速排序思想----分治法也确实实用,因此很多软件公司的笔试面试,包括像腾讯,微软等知名IT公司都喜欢考这个,还有大大小的程序方面的考试如软考,考研中也常常出现快速排序的身影
    2022-05-05
  • Qt禁止程序多开的实现示例

    Qt禁止程序多开的实现示例

    本文主要介绍了Qt 禁止程序多开的实现示例,主要介绍了三种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-09-09
  • C++相交链表和反转链表详解

    C++相交链表和反转链表详解

    这篇文章主要介绍了C++相交链表和反转链表,结合实例形式分析了C++相交链表和反转链表的原理、实现方法及相关注意事项,需要的朋友可以参考下
    2021-08-08

最新评论