C ++ Struct to Byte *抛出错误

时间:2017-11-08 16:41:13

标签: c++ serialization struct

我已在下面附上我的代码。我不明白我做错了什么。我有一个结构,我试图序列化为一个字节数组。我写了一些简单的代码来测试它。当我打印出对象的值时,它似乎都在运行时工作,但是一旦我点击返回0就会抛出错误:

运行时检查失败#2 - 变量'command'周围的堆栈已损坏。

我没有看到这个问题。我感谢所有的帮助。

namespace CommIO
{
    enum Direction {READ, WRITE};

    struct CommCommand
    {
        int command;
        Direction dir;
        int rwSize;
        BYTE* wData;

         CommCommand(BYTE* bytes)
        {
            int offset = 0;
            int intsize = sizeof(int);

            command = 0;
            dir = READ;
            rwSize = 0;

            memcpy(&command, bytes + offset, intsize);
            offset += intsize;
            memcpy(&dir, bytes + offset, intsize);
            offset += intsize;
            memcpy(&rwSize, bytes + offset, intsize);
            offset += intsize;

            wData = new BYTE[rwSize];
            if (dir == WRITE)
            {   
                memcpy(&wData, bytes + offset, rwSize);
            }
        }

        CommCommand() {}
    }

int main()
{
    CommIO::CommCommand command;
    command.command = 0x6AEA6BEB;
    command.dir = CommIO::WRITE;
    command.rwSize = 128;
    command.wData = new BYTE[command.rwSize];
    for (int i = 0; i < command.rwSize; i++)
    {
        command.wData[i] = i;
    }

    command.print();

    CommIO::CommCommand command2(reinterpret_cast<BYTE*>(&command));
    command2.print();
    cin.get();
    return 0;
}

4 个答案:

答案 0 :(得分:0)

目前

memcpy(&wData, bytes + offset, rwSize);

从wData指针的位置复制到新CommCommand的wData指针的位置。但是您希望从指针指向的位置进行复制。你需要取消引用。你破坏了堆,因为你只有sizeof(BYTE *)空间(加上一些额外的,因为堆块不能任意小),但你复制了rwSize字节,即128字节。你可能想写的是:

memcpy(wData, *(BYTE*)(bytes + offset), rwSize);

将使用存储在bytes + offset处的指针,而不是bytes + offset本身的值。

您还假设您的结构紧密包装。但是,C ++并不能保证这一点。您是否有理由不覆盖默认的复制构造函数而不是编写此函数?

答案 1 :(得分:0)

结构的内存布局没有填充,这可以通过在结构的开头添加宏#pragma pack(1)并在结构的末尾添加#pragma pop()来解决 - 检查它的语法

对于struct to byte转换,我会使用简单的东西:

template<typename T, typename IteratorForBytes>
void ConvertToBytes(const T& t, IteratorForBytes bytes, std::size_t pos = 0)
{
    std::advance(bytes, pos);
    const std::size_t length = sizeof(t);
    const uint8_t* temp = reinterpret_cast<const uint8_t*>(&t);
    for (std::size_t i = 0; i < length; ++i)
    {
        (*bytes) = (*temp);
        ++temp; 
        ++bytes;
    }
}

T是你的Command结构和bytes结构的结构。

CommIO::CommCommand command;
command.wData = new BYTE[command.rwSize];
ConvertToBytes(command, command.wData); 

结果数组将包含预期的bytes如果要从特定位置开始填充字节数组,可以指定偏移量和额外参数

答案 2 :(得分:0)

主要问题在于:

memcpy(&wData, bytes + offset, rwSize);

成员wDataBYTE *,您似乎意味着将字节复制到它指向的空间。而是将数据复制到存储指针值本身的内存中。因此,如果复制的字节数多于指针大小,则会超出其边界并产生未定义的行为。在任何情况下,您都在废弃原始指针值。你可能想要这个,而不是:

memcpy(wData, bytes + offset, rwSize);

此外,尽管反序列化代码的其余部分可能适合您的实际序列化格式,但假设它适合您在测试程序中通过

呈现给它的字节序列是不安全的。
CommIO::CommCommand command2(reinterpret_cast<BYTE*>(&command));

正如评论中所详述的那样,您对C ++不保证的CommIO::CommCommand内存布局做出了假设。

答案 3 :(得分:0)

评论中提到的以下几点很可能是导致问题的原因。

  1. 您似乎假设Direction的大小与int的大小相同。情况确实如此,但C ++并不能保证。

  2. 你似乎也假设CommIO::CommCommand的成员将被放置在内存中而没有任何填充,这可能恰好是这种情况,但不能保证。

  3. 有几种方法可以解决这个问题。

    1. 确保使用匹配的对象填充调用函数中的BYTE数组,或

    2. 只需将BYTE*转换为CommCommand*并直接访问这些成员。

    3. 对于(1),您可以使用:

      int command = 0x6AEA6BEB;
      int dir = CommIO::WRITE;
      int rwSize = 128;
      
      totatlSize = rwSize + 3*sizeof(int);
      BYTE* data = new BYTE[totalSize];
      
      int offset = 0;
      memcpy(data + offset, &comand, sizeof(int));
      offset += sizeof(int);
      memcpy(data + offset, &dir, sizeof(int));
      offset += sizeof(int);
      memcpy(data + offset, &rwSize, sizeof(int));
      offset += sizeof(int);
      
      for (int i = 0; i < rwSize; i++)
      {
         data[i + offset] = i;
      }
      
      CommIO::CommCommand command2(data);
      

      对于(2),您可以使用:

      CommCommand(BYTE* bytes)
      {
         CommCommand* in = reinterpret_cast<CommCommand*>(bytes);
      
         command = in->command;
         dir = in->dir;
         rwSize = in->size;
      
         wData = new BYTE[rwSize];
         if (dir == WRITE)
         {   
            memcpy(wData, in->wData, rwSize);
         }
      }
      

      另一个错误是你正在使用

      memcpy(&wData, bytes + offset, rwSize);
      

      这是不正确的,因为您正在处理变量的地址,就像它可以保存数据一样。它不能。

      您需要使用:

      memcpy(wData, bytes + offset, rwSize);