2

我在 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 打包结构会有什么不同吗?

4

2 回答 2

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

这显然不是你想要的。

在搜索了 about 之后#pragma pack,它似乎对这个案例有所帮助。编译器不会插入填充(尽管它实现定义的......),因此(很可能)会正确读取和写入值。

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

于 2013-07-03T17:16:49.827 回答
1

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

static_assert(sizeof(StructOfInts) == (3 * sizeof(int)), "size mismatch");

完成此操作(IMO)的最佳方法是使用对称形式:逐个字段序列化,然后逐个字段反序列化。

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

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

因此,固定宽度类型、显式字节顺序和逐字段对称序列化通常是您所需要的。

于 2013-07-03T17:22:53.613 回答