class Config_Cell
{
public:
char MN[14];
unsigned char ST[2];
unsigned int SampleInterval;
unsigned int ReportInterval; //4 上报周期=采集周期
unsigned int StoreInterval; //4 历史数据存储周期
char CallNum[16];
char PassWord[6];
unsigned int OverTime; //4 超时时间
unsigned int ReCount; //4 重发次数
unsigned int AlarmConfirmTime; //4 超限报警时间
unsigned char IPandPort1[20]; //4 IP & Port- 192.168.001.001.5002
unsigned char IPandPort2[20]; //4 IP & Port- 192.168.001.001.5002
unsigned char LocalIP[4]; //4 Local IP
unsigned char GateWay[4];
unsigned char FixRepTime[2]; //4 fixed Report time
unsigned char ReportEnabeled:6; //4前5位 6 -unitControl
unsigned char LocalCode:2; //地方代码: 旧版本0,国家 1 ,河南2
};
class saveConfigType
{
public:
Config_Cell config;
unsigned short CRC;
public:
bool CrcCheck(); //4 比较计算Config得到的CRC 和.CRC是否一致
};
系统最终把一个saveConfigType类型存储在NorFlash中,注意还加上了crc校验。
在取出参数时,取出crc检验值,然后再根据Config_Cell config 计算出一个crc 值,如果这两个值相等,
则认为参数是有效的。
但在实际使用中却出现了问题,该问题是由结构体对齐导致的:
修改了Config_Cell 的定义,删掉了unsigned int SampleInterval 变量。
按照我的想法,crc校验值应该比对不正确,但是实际上,crc校验值比对依然是正确的,
这就导致了取出来的参数成了随机数,系统无法正常工作。
分析其原因是这样的,
虽然类Config_Cell 的实际长度变了,但是由于对齐的原因,sizeof(Config_Cell)的结果却没有发生变化,
sizeof(saveConfigType)的结果也没有发生变化
而CRC所存储在NorFalsh中的位置也没有发生变化,saveConfigType.CRC的位置也没有发生变化,
而crc校验值比对的算法是:取出sizeof(Config_Cell)长度的内容,进行crc计算,算出的值与saveConfigType.CRC
进行比较。这也自然是对的。
关于结构对齐的详细解释是这样的:
//////////////////////////////////////////////////////////////////////////////////////////
以下为转贴的内容:
#pragma pack(4)
TestB class
{
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的理解是错误的。
#pragma pack规定的对齐长度,实际使用的规则是:
结构,联合,或者类的数据成员,第一个放在偏移为0的地方,以后每个数据成员的对齐,按照#pragma pack指定的数值和这个数据成员自身长度中,比较小的那个进行。
也就是说,当#pragma pack的值等于或超过所有数据成员长度的时候,这个值的大小将不产生任何效果。
而结构整体的对齐,则按照结构体中最大的数据成员 和 #pragma pack指定值 之间,较小的那个进行。
具体解释
#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。