• 把单一元素的数组放在一个struct的尾端


    1. 出现本文的原因

    2. 介绍 这种技巧

    3. 修改书中的错误

    1. 出现本文的原因

    在《深度探究c++对象模型》看到这样一段代码:

    1 struct mumble {
    2   /* stuff */
    3   char pc[ 1 ];
    4 };
    5 // grab a string from file or standard input
    6 // allocate memory both for struct & string
    7 struct mumble *pmumb1 = ( struct mumble* ) malloc(sizeof(struct mumble)+strlen(string) + 1);  
    8 strcpy( &pmumb1.pc, string );

    在那本书中并不是为了介绍 "把单一元素的数组放在一个struct的尾端问题" 的这个trick的。但在看项目中服务器发包给客户端的时候,也用到了这种格式,为什么要这么写,分析记录一下。

    2. 介绍 这种技巧

    简化项目中例子:

    定义一个可变包结构&&如何往可变包结构中填充数据。

    #pragma pack(1)
    typedef unsigned char BYTE;
    // 1. 定义一个 送花排行信息 包结构 。结构体的最后是 只含一个元素的一维数组。
    struct FlowerRank
    {
        // 2. 定义 排行信息单元,玩家名字和被送花数目 也就是 可变单元里 的元素的结构。 
        struct RankUnit 
        {
            char szName[32];
            int iNum;
            RankUnit()
            {
                memset(szName, 0, 32 * sizeof(char));
                iNum = 0;
            }
        };
        BYTE packetType;     // 指明此消息的类型 方便接收方解析消息。
        RankUnit rankData[1]; // 排行信息单元 从这里开始存。注:此变量也可成 char rankData[1];
    };
    
    // 
    int main()
    {
    // 获取下结构体的大小
    int a = sizeof(FlowerRank); // 37 size //注:如果 char rankData[1] ,那么 sizeof(FlowerRank) = 2 size; a = sizeof(FlowerRank::RankUnit); // 36 size   
      
       // 3. 根据需要塞入的 排行信息单元的 数目多少,申请对应的内存空间。
    const int iCounts = 10; // 10个单元 // 占了一段内存,在此上对应结构体成员。 pData 大小 361 char pData[sizeof(FlowerRank::RankUnit) * (iCounts -1) + sizeof(FlowerRank)] = { 0 }; // 注:如果 char rankData[1] ,那么 // char pData[sizeof(FlowerRank::RankUnit) * iCounts + sizeof(FlowerRank) - 1] = { 0 }; a = sizeof(pData); // 361 size

       // 4. 在申请的空间上 定义变量类型 如何读取内存 FlowerRank* pPacket = new (pData) FlowerRank; FlowerRank::RankUnit* pRankList = new (pPacket->rankData) FlowerRank::RankUnit[iCounts]; // 5. 塞入实际的信息。为了方便书写10个都填入一样的数据了 for (int i = 0; i < iCounts; ++i) { strncpy_s(pRankList[i].szName, "Goddess", 32); pRankList[i].iNum = 10; } // 6. 发送包
    pPacket
     return 0; }

    可以看到定义可变包结构时候,结构中没有可变包的大小,而是只要在结构里最后加一个元素的字节数组就可以。(也可以加一个元素的 信息单元结构的数组,这样方便理解,但是结构体大小会大点)。

    这个技巧利用了两点:

    1) struct在内存中的布局。

    2) 指针之间的相互转换,内存地址可以按照不同类型的数据来解释。

     这里有一个问题:把

     RankUnit rankData[1] ----》RankUnit* rankData; 会怎么样?
    char rankData[1] ----》char* rankData; 会怎么样?

    这样整个结构体的数据是不连续的的。改变成指针后指向了另外一块内存,而不是和结构体的其他数据成员连续存放了。

    3. 修改书中的错误

    struct mumble {
       /* stuff */
       char pc[ 1 ];

    };
    // 0. 注意下面的 string不是类型,是实际字符串。
    // 1. 去掉 + 1, 因为尽管strlen是不包括的,但因为pc中已经有一个字节了,所以这里不需要再加1了。当然加1也不会有问题,只是没有必要而已。
    struct mumble *pmumb1 = ( struct mumble* ) malloc(sizeof(struct mumble)+strlen(string) + 1);
    struct mumble *pmumb1 = ( struct mumble* ) malloc(sizeof(struct mumble)+strlen(string));
    // 2. pmumbl是指针,应该用->;而且pc是指针了,也不能再取地址了。
    strcpy( &pmumb1.pc, string );
    strcpy_s(pmumb1->pc,strlen(string) + 1, string);
  • 相关阅读:
    ASP.Net设计时需要考虑的性能优化问题 转载自http://blog.sina.com.cn/s/blog_3d7bed650100055p.html
    Jqeruy dropdownlist 联动
    Sound Recording in Windows Phone 7
    Windows Phone Performance 系列网址集合
    【xml]: Read XML with Namespace resolution using XLinq.XElement
    编程基础字符篇(2)
    每日总结一:
    每日总结5:
    Control usage: (1) Windows Phone 7: Popup control
    编程基础字符篇(3)
  • 原文地址:https://www.cnblogs.com/fulina/p/6003872.html
Copyright © 2020-2023  润新知