我已在下面附上我的代码。我不明白我做错了什么。我有一个结构,我试图序列化为一个字节数组。我写了一些简单的代码来测试它。当我打印出对象的值时,它似乎都在运行时工作,但是一旦我点击返回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;
}
答案 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);
成员wData
是BYTE *
,您似乎意味着将字节复制到它指向的空间。而是将数据复制到存储指针值本身的内存中。因此,如果复制的字节数多于指针大小,则会超出其边界并产生未定义的行为。在任何情况下,您都在废弃原始指针值。你可能想要这个,而不是:
memcpy(wData, bytes + offset, rwSize);
此外,尽管反序列化代码的其余部分可能适合您的实际序列化格式,但假设它适合您在测试程序中通过
呈现给它的字节序列是不安全的。CommIO::CommCommand command2(reinterpret_cast<BYTE*>(&command));
正如评论中所详述的那样,您对C ++不保证的CommIO::CommCommand
内存布局做出了假设。
答案 3 :(得分:0)
评论中提到的以下几点很可能是导致问题的原因。
您似乎假设Direction
的大小与int
的大小相同。情况确实如此,但C ++并不能保证。
你似乎也假设CommIO::CommCommand
的成员将被放置在内存中而没有任何填充,这可能恰好是这种情况,但不能保证。
有几种方法可以解决这个问题。
确保使用匹配的对象填充调用函数中的BYTE
数组,或
只需将BYTE*
转换为CommCommand*
并直接访问这些成员。
对于(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);