字节对齐
随着半导体技术的发展,我们经历8bit、16bit、32bit乃至64bit的CPU,我们产品当前大多使用32bit CPU
从内存存取效率来说,4字节对齐的存取速度是最快的,非对齐情况下,CPU需要分解成两次32bit操作;
缺省情况下,编译器自动对数据结构进行四字节对齐,以提高程序执行的效率,在特殊情况
下,可以通过预编译指定指定数据结构为1字节对齐或者其他;
对于Power PC/Intel系列CPU,在非四字节对齐情况下,由CPU自动完成两次操作,对上层应用透明;对于MIPS CPU,则需要通过编译选项进行干预,或者调整数据结果避免出现这种情况,否则会产生例外;
字节对齐对数据结构的尺寸(sizeof)直接产生影响
**********************
#pragma pack(4)
class TestB
{
public:
int aa;
char a;
short b;
char c;
};
int nSize = sizeof(TestB);
这里nSize结果为12,在预料之中。
现在去掉第一个成员变量为如下代码:
#pragma pack(4)
class TestC
{
public:
char a;
short b;
char c;
};
int nSize = sizeof(TestC);
按照正常的填充方式nSize的结果应该是8,为什么结果显示nSize为6呢,
具体解释
#pragma pack(4)
class TestB
{
public:
int aa; //第一个成员,放在[0,3]偏移的位置,
char a; //第二个成员,自身长为1,#pragma pack(4),取小值,也就是1,所以这个成员按一字节对齐,放在偏移[4]的位置。
short b; //第三个成员,自身长2,#pragma pack(4),取2,按2字节对齐,所以放在偏移[6,7]的位置。
char c; //第四个,自身长为1,放在[8]的位置。
};
这个类实际占据的内存空间是9字节
类之间的对齐,是按照类内部最大的成员的长度,和#pragma pack规定的值之中较小的一个对齐的。
所以这个例子中,类之间对齐的长度是min(sizeof(int),4),也就是4。 9按照4字节圆整的结果是12,所以sizeof(TestB)是12。
如果
#pragma pack(2)
class TestB
{
public:
int aa; //第一个成员,放在[0,3]偏移的位置,
char a; //第二个成员,自身长为1,#pragma pack(4),取小值,也就是1,所以这个成员按一字节对齐,放在偏移[4]的位置。
short b; //第三个成员,自身长2,#pragma pack(4),取2,按2字节对齐,所以放在偏移[6,7]的位置。
char c; //第四个,自身长为1,放在[8]的位置。
};
//可以看出,上面的位置完全没有变化,只是类之间改为按2字节对齐,9按2圆整的结果是10。
//所以 sizeof(TestB)是10。
最后看题:
现在去掉第一个成员变量为如下代码:
#pragma pack(4)
class TestC
{
public:
char a;//第一个成员,放在[0]偏移的位置,
short b;//第二个成员,自身长2,#pragma pack(4),取2,按2字节对齐,所以放在偏移[2,3]的位置。
char c;//第三个,自身长为1,放在[4]的位置。
};
//整个类的大小是5字节,按照min(sizeof(short),4)字节对齐,也就是2字节对齐,结果是6
//所以sizeof(TestC)是6。
#pragma pack规定的对齐长度,实际使用的
规则
编码规则下载淘宝规则下载天猫规则下载麻将竞赛规则pdf麻将竞赛规则pdf
是:
结构,联合,或者类的数据成员,第一个放在偏移为0的地方,以后每个数据成员的对齐,按照#pragma pack指定的数值和这个数据成员自身长度中,比较小的那个进行。 也就是说,当#pragma pack的值等于或超过所有数据成员长度的时候,这个值的大小将不产生任何效果。
而结构整体的对齐,则按照结构体中最大的数据成员 和 #pragma pack指定值 之间,较小的那个进行。
************************************* struct bbb
{
long num;
char *pcname;
short sdate;
char cha[2];
short sba[6];
}*p;
p=0x100000;
p+0x1=0x____?
(unsigned long)p+0x1=0x___?
(unsigned long*)p+0x1=0x___?
(char*)p+0x1=0x___?
p = 0x1000000; //p 是一个指针类型的结构体
p+0x01 = 0x100000 + sizeof(struct bbb)
(unsigned long)p + 0x1 = 0x1000001 ; //p是一个unsigned long类型的变量,只需要相加
(unsigned long*)p + 0x1 = 0x1000000 + sizeof(unsigned long)
= 0x1000004
(char*)p + 0x1 = 0x1000000 + sizeof(char) = 0x1000001
对指针进行算术运算,是按指针所指向的结构体所占大小进行运算的
对指针进行强制转换成整型后,就只按其算术值进行计算
************************************************
struct tagAAA
{ unsigned char ucId:1;
unsigned char ucPara0:2;
unsigned char ucState:6;
unsigned char ucTail:4;
unsigned char ucAvail;
unsigned char ucTail2:4;
unsigned long ulData; }AAA_S;
问:AAA_S在字节对齐分别为1、4的情况下,占用的空间大小是多少, 答案:9 12
a、1字节对齐:
struct tagAAA
{
unsigned char ucId:1;
unsigned char ucPara0:2;,,,,占用1个char
unsigned char ucState:6;,,,,占用1个char
unsigned char ucTail:4;,,,,占用1个char
unsigned char ucAvail;,,,,占用1个char
unsigned char ucTail2:4;,,,,占用1个char
unsigned long ulData;,,,,占用4个char }AAA_S;
所以是9
b、4字节对齐:
struct tagAAA
{
unsigned char ucId:1;
unsigned char ucPara0:2;,,,,占用1个char
unsigned char ucState:6;,,,,占用1个char
unsigned char ucTail:4;,,,,占用1个char
unsigned char ucAvail;,,,,占用1个char ,,,,,,,,,,,,,,,,,,,,,,,,,
unsigned char ucTail2:4;,,,,占用1个char 这里会补充3个char
,,,,,,,,,,,,,,,,,,,,,,,
unsigned long ulData;,,,,占用4个char
}AAA_S;
所以是12
在VC下面运行,由于没有强制制定对齐模式,默认就是4字节对齐,所以是12