代码编织梦想

目录

前言

一、什么是字节对齐?

二、结构体字节对齐

三、#pragma pack()的使用

总结

结语

封面


前言

        本教程可能会用到一点汇编的知识,看不懂没关系,知道是那个意思就行了。使用的工具是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的整数倍,所以它和char t的差值应该为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)即可。

结语

        感谢大家观看!听不懂的地方可以提问,讲错了的地方请指出。

封面

 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_52572621/article/details/127157452

c语言结构体字节对齐规则_annjeff的博客-爱代码爱编程_c结构体字节对齐规则

C语言结构体字节对齐规则 基本规则 规则1 :结构体(struct)的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存放在offset为该数据成员大小的整数倍的地方(比如int在32位机为4字

c语言结构体字节对齐详解_每天学一点!的博客-爱代码爱编程_c语言 结构体对齐

转载地址:http://c.biancheng.net/view/243.html   问大家一个问题: struct STUDENT { char a; int b; }data; 如上结构体变量 data 占多少字节?char 占 1 字节,int 占 4 字节,所以总共占 5 字节吗?我们写一个程序验证一下: #includ

c语言结构体中字节对齐-爱代码爱编程

引言:曾经一个面试官向我提了如下问题,当时没答上,事后调试了一下,总结下经验。 基本代码: struct test {   char a;   int b; }*ptr; ptr = (struct test*)0x1000000; 问题: ptr+1=?; (unsigned long)ptr+1=?; (int *)ptr+1=?; 在

Linux+c语言结构体对齐,详解linux下C语言结构体对齐(内存对齐问题)-爱代码爱编程

详解C语言结构体对齐(内存对齐问题) C语言结构体对齐也是老生常谈的话题了。内容虽然很基础,但一不小心就会弄错。我在刚开始接触的时候也会是很迷糊,通过编译器运行的结果总是和自己的不一样,使自己很苦恼。在网上查了很多的资料,但是说的都很迷糊,但是内存对齐是怎么回事呢?我将网上所说的东西和自己的了解总结一下,其实理解后是非常简单的东西。 首先说一下内存

c语言让结构体一字节对齐的代码,C语言结构体变量字节对齐问题总结-爱代码爱编程

结构体字节对齐 在用sizeof运算符求算某结构体所占空间时,并不是简单地将结构体中所有元素各自占的空间相加,这里涉及到内存字节对齐的问题。从理论上讲,对于任何 变量的访问都可以从任何地址开始访问,但是事实上不是如此,实际上访问特定类型的变量只能在特定的地址访问,这就需要各个变量在空间上按一定的规则排列, 而不是简单地顺序排列,这就是内存对齐。 内

c语言结构体的字节对齐,关于c:c语言结构体字节对齐详解-爱代码爱编程

1.什么是字节对齐 在c语言的构造体外面个别会依照某种规定去进行字节对齐。 咱们先看一段代码: struct st1 { char name; double age; char sex; }; //32位下 sizeof(struct st1) = 16 //64位下 sizeof(struct st1) = 24 struct

C语言结构体的字节对齐原则,c语言结构体字节对齐详解-爱代码爱编程

1.什么是字节对齐 在c语言的结构体里面一般会按照某种规则去进行字节对齐。 我们先看一段代码:struct st1 { char name; double age; char sex; }; //32位下 sizeof(struct st1) = 16 //64位下 sizeof(struct st1) = 24 struct st

C语言字节对齐的计算 图解,C语言结构体字节对齐简单计算方法-爱代码爱编程

1.在C语言里面每一种数据类型都有字节对齐比如在32位操作系统下:整型的自身对齐数就是 4 字节,字符型就是 1 字节,double就是 8 字节。 但是结构体的计算方式就和普通的数据类型不一样。 在C语言里面字节对齐的方式主要根据“有效对齐数”来确定,那么有效对齐数是怎杨确定的呢? 在结构体里面::: 有效字节对齐数 = (自身对齐数 <

C语言结构体字节对齐-爱代码爱编程

????????关注后回复 “进群” ,拉你进程序员交流群???????? 作者丨写代码的牛顿 来源丨编程学习总站 01 — 默认字节对齐 C语言结构体字节对齐是老生常谈的问题了,也是高频面试题,现在我们来深入研究这个问题,彻底弄懂到底是怎么回事,给你一个结构体定义和平台机器位数就能手动计算出结构体占用字节数,现在我们不使用宏#pragm

c语言结构体字节对齐规则-爱代码爱编程

结构体大小 struct Node { char cha; int a; char chb; }; int main() { struct Node nd = {'a',100,'b'}; int size1 = sizeof(nd); int size2 = sizeof(struct Node); int size3 = sizeof

c语言-爱代码爱编程

由于结构体存在字节对齐,所以结构体所占字节大小不是其各成员所占字节数之和!! 例1:下面程序结果为12,不是6! #include<stdio.h> struct Node { char cha; int ia; char chb; }; int main() { struct Node sd; printf("%d\n", si