字节对齐详解--C++/C#版本


面试考察频率:⭐⭐⭐⭐⭐

什么是字节对齐?

  计算机中内存都是按字节划分的,字节对齐就让各类数据在按照特定的规则在内存中排列。如果一个数据在内存中的位置刚好是他自身长度的整数倍,则为字节对齐。

为什么要进行字节对齐?

为了可以解决CPU读写数据效率的问题
  因为每个平台CPU所读取的字节数是不同的,例如一个平台每次总是读取4个字节,又有如下结构体:

struct Test
{
    int a;
    short b;
    double c;
};

  ⚪如果不进行内存对齐(不对齐采用1字节对齐),该结构体在内存中排列方式如下图所示(int 4字节,short 2字节,double 8字节):
在这里插入图片描述
这时候CPU取数据可能要执行两次或多次内存访问,降低效率。

  ⚪如果进行内存对齐(这里采用8字节对齐),该结构体在内存中排列方式如下图所示:
在这里插入图片描述
这里我们就发现读取数据可以很方便的每次从4的倍数字节开始的地方进行读取,提升了读取效率。

为了解决跨平台数据数据读取问题
  有的人开发时可能会遇到,明明在自己机器上可以正常运行读取数据,但到了别的平台无法读取各种奇怪的问题。这里就很有可能不同平台的CPU数据读取方式不同,又加之没有进行特定的字节对齐处理所导致的。所以一般跨平台可以使用1字节对齐,节省空间,但是效率过低。

如何实现字节对齐?

在c++中
  主要通过 #pragma pack(n) 来实现
常用字节对齐指令如下:

指令 效果
#pragma pack (n) 作用:C编译器将按照n个字节对齐。
#pragma pack () 作用:取消自定义字节对齐方式。
#pragma pack (push,n) 作用:是指把原来对齐方式设置压栈,并设新的对齐方式,n不填就是不设置新的对齐方式
#pragma pack(pop) 作用:恢复对齐状态

还是上面的代码,我们使用四字节对齐:

#pragma pack(4)
struct Test
{
    int a;
    short b;
    double c;
};

运行结果为16。画图表示:在这里插入图片描述
在c#中
主要通过 [StructLayout(LayoutKind.Sequential,CharSet =CharSet.Ansi,Pack =8)] 来实现。
还是上面的代码,在C#中,也采用4字节对齐

 [StructLayout(LayoutKind.Sequential,CharSet =CharSet.Ansi,Pack =4)]
    struct Test
    {
        int a;
        short b;
        double c;
    }
    static void Main(string[] args)
    {
        int i = 1;
        int size = Marshal.SizeOf(t);
        Console.WriteLine(size);
    }

和上面c++运行结果一样,都为16。

讲完了吗,不还没有,神奇的问题出现了。
还是刚才的代码,顺序稍微换一下,分别采用4字节和8字节对齐,可以猜猜看各自是多少。

//#pragma pack(4)
#pragma pack(8)
struct Test
{
    int a;
    double c;
    short b;
};

结果为一个16字节(4字节对齐),一个24字节(8字节对齐)。
是的,结果体内部字段的排列顺序会影响字节对齐所占空间大小。(当然如果都用1字节对齐那没有什么关系,但效率可想而知~)。
所以得出结论,结构体内部字段顺序,字节数越小的最好放在最上边

基础向的文章,欢迎大家一起学习讨论。


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM