首先,我们要知道什么是字节对齐。
字节对齐:现代计算机中内存空间都是按照BYTE划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列,而不是顺序的一个接一个的排放,这就是对齐。
为什么要字节对齐:因为各个硬件平台对存储空间的处理是不同的。一些平台对一些特定类型的数据只能从某些特定的地址开始存取。比如有些架构的cpu在访问一个没有对齐的变量的时候就会发生错误,那么在这种平台下编程就必须保证字节对齐,但是其他的平台可能就不用,但是如果不按照平台要求的对数据对齐,那么就会在存取效率上带来损失。例如,有的平台每次读数据都是从偶数地址开始的,如果有一个int型的数据(32位系统)存放子偶数开始的地址,那么只用读一个周期就可以了,但如果放在了奇数开始的地址,那么就需要两个周期。
字节对齐要区分四个概念:
1、 基本数据类型的自身对齐值:
1字节:char型
2字节:short型
4字节:int float类型
8字节:double类型
自身长度,如char=1,short=2,int=4,double=8,。所谓自对齐,指的是该成员的起始位置的内存地址必须是它自身长度的整数倍。如int只能以0,4,8这类的地址开始
2、程序的指定对齐值:即#pragma pack(value)时的指定对齐值value
3、自定义类型的自身对齐值:结构体或类的成员中自身对齐值最大的值
4、自定义类型的有效对齐值:自定义类型的自身对齐值和指定对齐值中较小的值
据此,我们就可以很方便的来讨论具体数据结构的成员和其自身的对齐方式。
eg:
Struct test
{
Char a;
Short b;
Char c;
};
上述结构体S的自身对齐值为2(b的自身对齐值),而指定对齐值为4(32位编译器默认值),故最终的有效对齐值为2.
然后我们来看看字节对齐在内存到底是怎么存储的,
eg:
struct AA
{
char a;
int b;
char c;
}aa
结果,sizeof(aa)=12
首先假设结构体内存起始地址位0,那么地址分布如下:
地址 数据
0 : a
1
2
3
4 : b
5 : b
6 : b
7 : b
8 : c
9
10
11
原因:
char的字对齐长度为1,所以可以在任何地址开始,但是,int自对齐长度为4,必须以4的倍数地址开始。所以,尽管1-3空着,但b也只能从4开始。再加上c后,整个结构体的总长度为9,结构体的有效对齐值为其中最大的成员即int的长度4,所以,结构体的大小向上扩展到12,即9-11的地址空着。
eg:
struct AA
{
char a;
char c;
int b;
}aa
sizeof(aa)=8,为什么呢
地址 数据
0 a
1 c
2
3
4 b
5 b
6 b
7 b
原因:
因为c为char类型,字对齐长度为1,所以可以有效的利用1-3间的空格。变量定义的位置的不同时有可能影响结构体的大小!
eg:
unsigned short *pucCharArray[10][10];
typedef union unRec
{
unsigned long ullndex;
unsigned short usLevel[7];
unsigned char ucPos;
}REC_S;
Rec_s stMax,*pstMax;
那么问:
四字节对齐时:
sizeof(pucCharArray)=( 400 )
sizeof(stMax)=( 16 )
sizeof(pstMax)=( 4 )
sizeof(*pstMax)=( 16 )
首先,这是一个联合体,且unsigned short *pucCharArray[10][10]是指针数组,即本质是个数组,但是数组中存放的都是指针,而指针是四个字节,那么sizeof(pucCharArray)=10*10*4=400;
对于联合体来说,几个数据是共享一块内存的,所以联合体的大小就是占内存空间最大那个数据的大小,并且,它的大小能被其他数据的大小所整除。
在本题中,题目要求是四字节对齐,在联合体本身也是按long对齐,所以有效对齐值还是4字节,unsigned long ullndex,占4字节,unsigned short usLevel[7]占14字节,unsigned char ucPos占1字节,所以取最大的是14字节,但14不能被4整除,所以14要加到可以被整除,即16。sizeof(pstMax)其实是求指针的大小,占4字节。sizeof(*pstMax)与sizeof(stMax)相同。
总之,内存对齐是会浪费一些空间的。但是这种空间上得浪费却可以减少取数的时间。这是典型的一种以空间换时间的做法。空间与时间孰优孰略这个每个人都有自己的看法,但是c语言既然采取了这种以空间换时间的策略,就必然有它的道理。况且,在存储器越来越便宜的今天,这一点点的空间上的浪费就不算什么了。