我在Visual Studio 2008中使用C ++。假设我有这样的结构:
struct StructOfInts
{
int a;
int b;
int c;
};
这意味着要像这样读写:
void Read( std::istream& is, StructOfInts& myStruct )
{
is.read( (char*)&myStruct.a, sizeof myStruct.a );
is.read( (char*)&myStruct.b, sizeof myStruct.b );
is.read( (char*)&myStruct.c, sizeof myStruct.c );
}
void Write( std::ostream& os, StructOfInts& myStuct )
{
os.write( (char*)&myStruct, sizeof myStruct );
}
上述代码在读取或写入文件时是否会导致某种内存损坏?由于内存损坏,我的意思是读入不正确的值。我正在尝试确定正在读入的-1。#QNB值的来源,并且想知道这是否可能是原因。 另外,如果我使用pragma pack打包结构会有区别吗?
答案 0 :(得分:2)
是的,由于struct
字段之间可能存在填充,您的代码可能导致读入无效值。让我们使用你的struct StructOfInts
的例子,并想象编译器在字段之间插入一些填充,如下所示:
byte | 0 1 2 3 | 4 5 | 6 7 8 9 | 10 11 12 13
value | field a | padding | field b | field c
然后,当您将结构体写入流时,最终可能会出现类似
的内容byte | 0 1 2 3 | 4 5 | 6 7 8 9 | 10 11 12 13
char | \0 \0 \0 'a' | '?' '?' | \0 \0 \0 'b' | \0 \0 \0 'c'
如果字段包含(分别)值(int)'a', (int)'b', (int)'c'
。
然后,当您重新读取值时,它看起来像
myStruct->a = int version of \0 \0 \0 'a'
myStruct->b = int version of '?' '?' \0 \0
myStruct->c = int version of \0 'b' \0 \0
这显然不是你想要的。
在搜索#pragma pack
后,看起来对这种情况有帮助。编译器不会插入填充(尽管是实现定义的......),因此值(很可能)可以正确读取和写入。
另外,另一件事是:如果你在一个系统(计算机/操作系统/编译器)上写,然后在另一个系统中读取数据,那么字节序问题也可能导致问题。
答案 1 :(得分:1)
测试此案例的快速方法是:
static_assert(sizeof(StructOfInts) == (3 * sizeof(int)), "size mismatch");
实现这一目标(IMO)的最佳方法是使用对称形式:逐个字段序列化,然后逐个字段反序列化。
简而言之,依赖于您的实现所使用的行为是依赖于目标体系结构的ABI,而不是标准(BAD)。因此,它可能导致“腐败”。
结构的大小可能因ABI而异,并且整数的大小甚至它们的字节顺序可能会有所不同 - 导致“损坏”。填充和对齐也由ABI指定。
因此,固定宽度类型,显式字节序以及字段对称序列化通常都是您需要的。