计算机字节对齐的理解
计算机字节对齐的理解
在计算机体系中,CPU的对内存的读取是按照CPU位数进行的,如32位则按4字节进行存取,64位则按8字节进行存取。如32位CPU总是按照,0X0001 0X0002 0X0003 0X0004(类推)为了保证数据的快速存取,编译器对程序中的数据进行的字节对齐,及让数据能够在计算机的一次取指令读取完毕。如果没按字节对齐存储,则有的数据将会是以奇字节地址开始,此时CPU需要两个CPU周期两次取址并对比高低字节对内存数据进行重组,这将导致性能上的损失。因此数据结构一般都采取字节对齐方式。
字节对齐方式
所谓字节对齐,就是数据按照特定的规定进行存储,在一般无规定的情况下(或许与CPU有关),编译器默认对齐字节为8位。
每个数据都有自己的对齐字节,数据必须在符合字节对齐字节的位置进行存储。将结构体开始位置设为0,各个对应的数据在相对于结构体开始位置的相对位置的编号能够被数据类型的大小整除,例如,在32位机器上,int 为4,char为1,相对于结构体开始位置可以为4,8,12……在一般情况不修改编译器默认字节,数据对齐字节即为其类型的大小。
如
struct example1{
char s;
short short1;
//int int1;
long long long1;
char c;
int n;
};
其大小为24个字节。
而如果使用 #pragma pack(x)修改了字节对齐的大小,则x则作为了一个分界线,如果数据类型小于x,则数据对应的字节对齐大小为相应的数据类型大小,如果大于x,则其对齐大小则为x。即说明,#pragma pack(x)起到了一个上限的作用。
字节对齐规则
在一个结构体中,除了相对的数据按照以上规则对字节做了对齐之外,还需要考虑整个结构体的对齐方式。譬如定义了一个结构体
struct st
{
int n;
char ch;
};
按照对应的字节对齐方式,n占用4个字节,ch占用一个字节,如果只按照以上规则,那么整个结构体的大小只有5个字节。但是,如果定义struct st ss[2],那么对第二个结构体ss[1]数据来说,第二个结构体的开始位置对应于最开始的位置来说为5,那么对s[1].n的数据的存取就需要两次读取周期了。解决这一情况便是对整个结构体再进行一次对齐,及取结构体中最大的数据类型与默认字节大小两者的最小值n进行对齐,使得整个结构体能大小能够整除n。
如果没有重新设定默认的字节对齐大小,一般则为结构体内对应的最大类型的大小,一般默认的字节大小即为最大数据类型大小。所以可以认为#pragma pack(x)是为了对结构体数据大小进行控制,设定了一个上限x。
例如上例,如果改变为:
#pragma pack(2)
struct st
{
int n;
char ch;
};
sizeof(st)的大小为6.
struct st
{
int n;
char ch;
};
struct stn
{
int n;
struct st;
char ch;
};
在结构体stn当中,struct st对应的字节大小不是整个结构体的大小,而只是对应的最大数据类型大小与字节大小的上限两者的最小值。
这样的方式能够解除在嵌套的st结构体当中填充的字节,让新结构体对其进行重新填充,提高空间利用率。
default pack:
sizeof(stn) = 16;
long long在32位CPU及64位CPU的对齐方式
long long在64位机子上,默认对齐方式下,字节对齐大小为8.
在32位机子上,未实验。