zoukankan      html  css  js  c++  java
  • 结构体对齐的具体含义

    系统需要存储一些参数,为了方便,把这些参数统一放到一个结构体中:
    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。




  • 相关阅读:
    SP是什么?CP是什么?SP与CP有什么区别?
    SP与CP将走向互补融合
    SP与CP分工
    Asynchronous Socket 顺序
    Asynchronous Client Socket Example
    Synchronous Server Socket Example
    web应用程序根目录
    简单socket服务(一)
    Asynchronous Server Socket Example
    Socket连接不上的问题
  • 原文地址:https://www.cnblogs.com/gaotaozhaolei/p/1200909.html
Copyright © 2011-2022 走看看