字节对齐

本文对字节对齐的原因是出于正确性或者效率方面不做讨论,只讨论C/C++中字节是如何对齐的。本文讨论基于Visual C++6.0,所有代码均在其上运行。

本文参考网上其它文章,例子与其大同小异,如果您认为侵犯您的版权敬请告知予以更改。

首先看下面的程序:

struct A { int a; char b; short c; }; struct B { char b; int a; short c; };

对于32位的系统,char类型为1个字节、int类型为4个字节、short2个字节,表面上看,sizeof(A)sizeof(B)都应该是7个字节才对,但运行的结果呢?前者长度为8,后者长度为12

之所以产生这样的结果,是因为默认情况下,编译器对结构的存储进行了对齐操作。

变量或者类型的对齐长度

对于基本类型,默认对齐长度即变量的字节数,如在32位系统中,char1个字节、int为个字节;

对于结构体、联合体、和类等自定义类型,对齐长度为其内部成员的最大对齐长度,如上面的结构体AB,其成员中a的对齐长度为4最大,则AB的对齐长度即为4

默认情况下,变量的存储首地址必须为其对齐长度的整数倍,如short2个字节,则short类型的变量只能从偶数地址开始存储。

现在回头来看结构AB的对齐,假使结构从地址0x0000处开始存储,对于结构A,第一个成员a为整形,占据0x0000~0x0003四个字节,第二个成员b为一个字节,存储在0x0004,第三个成员c占两个字节,必须从偶数开始存储,因此0x0005被跳过,c被存储在0x00060x0007中。因此sizeof(A)的结果为8

对于结构B,第一个成员占1个字节,存储在0x0000中,第二个成员a为整形,4个字节,存储的起始地址必须为4的整数倍,因此0x0001~0x0003被跳过,a被存储在0x0004~0x0007中,第三个成员c占两个字节,存储在0x00080x0009中。从0x00000x0009应为10个字节,sizeof(B)的结果为什么会是12呢?

考虑如下的情形:

struct B bArray[10];

由于数组是按顺序存储的,第一个元素占据从0x00000x0009这十个字节,第二个元素存储的时候,由于结构B的对齐长度为4,因此必须从0x000C处开始存储,则0x000A0x000B被闲置,数组存储将不再连续,因此从数组存储的角度,编译器将0x000A0x000B保留在结构B中,如此以来,数组中元素的存储就连续了。也就是说,结构的长度必须为该结构对齐长度的整数倍。

改变默认对齐长度

#pragma pack(n)

#pragma pack()

来改变默认的对齐长度,n的取值为124816,被称为有效对齐长度。但如果n大于结构的对齐长度将按默认的对齐长度存储。比如下面的例子:

#pragma pack(8)

struct C

{

char b;

int a;

short c;

};

#pragma pack()

因为n=8大于C的对齐长度4,则sizeof(C)的值为12而不是3*8=24。如果n=1,则sizeof(C)的值为7n=2则为8

 

此文档只讨论字节如何对齐,对于字节对齐的理由以及由字节对齐而引起的问题,百度一下。对于具体的硬件平台,字节对齐大部分已由编译器自动实现,不同的编译器实现的结果可能和本文说明的不一致,请参考具体平台的说明。

 

你可能感兴趣的:(学习笔记,存储,编译器,struct,平台,c,文档)