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++递归实现选择排序算法

    C++递归实现选择排序算法

    大家好,本篇文章主要讲的是C++递归实现选择排序算法,感兴趣的同学赶快来看一看吧对你有帮助的话记得收藏一下,方便下次浏览
    2021-12-12
  • C++实现LeetCode(47.全排列之二)

    C++实现LeetCode(47.全排列之二)

    这篇文章主要介绍了C++实现LeetCode(47.全排列之二),本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-07-07
  • C++获取GPU显卡信息的示例代码

    C++获取GPU显卡信息的示例代码

    这篇文章主要为大家详细介绍了如何使用C++获取GPU显卡信息,文中的示例代码讲解详细,具有一定的借鉴价值,有需要的小伙伴可以参考一下
    2024-02-02
  • C++ static详解,类中的static用法说明

    C++ static详解,类中的static用法说明

    这篇文章主要介绍了C++ static详解,类中的static用法说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-07-07
  • C语言的Struct Hack笔记

    C语言的Struct Hack笔记

    这篇文章主要介绍了C语言的Struct Hack例子,个人的一篇笔记,需要的朋友可以参考下吧
    2014-04-04
  • 详解C语言编程中的函数指针以及函数回调

    详解C语言编程中的函数指针以及函数回调

    这篇文章主要介绍了C语言编程中的函数指针以及函数回调,函数回调实际上就是让函数指针作函数参数、调用时传入函数地址,需要的朋友可以参考下
    2016-04-04
  • C语言简明分析指针与引用的具体用法

    C语言简明分析指针与引用的具体用法

    指针是一个实体,引用是一个别名;在汇编上,引用的底层是以指针的方式实现的,定义一个引用变量,相当于定义了一个指针,然后把引用内存的地址写到这个指针里面,当通过引用变量修改它所引用的内存时,它先访问了指针里面的地址,然后在这个地址的内存里面对值进行修改
    2022-05-05
  • C语言实现电子时钟程序

    C语言实现电子时钟程序

    这篇文章主要为大家详细介绍了C语言实现电子时钟程序,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-11-11
  • c++ 类函数作为模板参数实现方式详解

    c++ 类函数作为模板参数实现方式详解

    这篇文章主要介绍了c++ 类函数作为模板参数实现方式,在实现中加入增强逻辑,这种方式对代码侵入性过高,而且无法控制该逻辑是否需要,如果不需要的话又得重新修改代码实现,需要的朋友可以参考下
    2023-03-03
  • 一篇文章带你了解C语言文件操作中的几个函数

    一篇文章带你了解C语言文件操作中的几个函数

    这篇文章主要介绍了使用C语言操作文件的基本函数整理,包括创建和打开以及关闭文件的操作方法,需要的朋友可以参考下,希望能够给你带来帮助
    2021-09-09

最新评论