C++;按字段读取结构并将结构直接写入流 我使用Visual Studio 2008的C++。假设我有这样一个结构: struct StructOfInts { int a; int b; int c; };

C++;按字段读取结构并将结构直接写入流 我使用Visual Studio 2008的C++。假设我有这样一个结构: struct StructOfInts { int a; int b; int c; };,c++,serialization,deserialization,abi,C++,Serialization,Deserialization,Abi,这意味着要像这样读和写: 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,

这意味着要像这样读和写:

    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 );
    }
在读取或写入文件时,上述代码是否会导致某种内存损坏?所谓内存损坏,我指的是读取的值不正确。我正试图确定正在读取的a-1.#QNB值的来源,我想知道这是否是原因。 另外,如果我使用pragma pack打包结构是否有区别?

是的,由于
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
之后,它似乎对这个案例有所帮助。编译器不会插入填充(尽管它是实现定义的…),因此(很可能)会正确读取和写入值


另外,还有一件事:如果您在一个系统(计算机/操作系统/编译器)上进行写操作,然后在另一个系统中读取数据,那么endianness问题也可能导致问题。

测试这种情况的快速方法是:

static_assert(sizeof(StructOfInts) == (3 * sizeof(int)), "size mismatch");
实现这一点的最佳方法(IMO)是使用对称形式:逐个字段序列化,然后逐个字段反序列化

简而言之,依赖实现使用的行为就是依赖目标体系结构的ABI,而不是标准(BAD)。因此,它可能导致“腐败”

结构的大小可能因ABI而异,而INT的大小甚至它们的字节顺序可能会有所不同——这会导致“损坏”。填充和对齐也由ABI指定


因此,您通常需要固定宽度类型、显式结尾和逐字段对称序列化。

不使用>>运算符有什么特殊原因吗?没有特殊原因。这就是我正在使用的(非常旧的)代码库的样子,这是为了保持一致性。我认为问题在于这一行:
os.write((char*)&myStruct,sizeof myStruct)。尝试逐个元素写入
ostream
。因为如果你在64位机器上,
sizeof(int)
将是32位,可能会有填充。当贾斯汀和费拉林发布他们的答案时,我就是这么想的。但是,当我将结构的大小与结构中各个字段的总大小进行比较时,它们是相同的。当您得到
-1时,您试图读取的值是多少。QNB
感谢您的回答。我尝试了静态断言(好主意,顺便说一句),但不幸的是(或幸运的是)它没有触发。你认为这是否意味着在我的特殊情况下,阅读/写作是正确的?我面临的问题非常不一致,可能与此有关,也可能与此无关。@k9ty如果在读取和写入这些文件(例如windows,32位)时只在一个体系结构上运行,那么问题可能在其他地方。您的程序只是告诉它对POD进行字节复制,大小一致。如果在多个平台/体系结构上运行,则允许序列化表示形式不同(即sizeof(int)甚至可能不相同)。