Question

I'm using C++ with visual studio 2008. Say I have a structure like so:

    struct StructOfInts
    { 
        int a;
        int b;
        int c; 
    };

That's meant to be read and written like so:

    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 );
    }

Can the above code result in some sort of memory corruption when reading from or writing to a file? By memory corruption, I mean incorrect values being read in. I'm trying to determine the source of a -1.#QNB value that's being read in and am wondering if this could be the cause. Also, is there a difference if I pack the structure using pragma pack?

Was it helpful?

Solution 2

The quick way to test this case is:

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

The best way to accomplish this (IMO) is to use a symmetric form: serialize field-by-field and then also deserialize field-by-field.

In short, to rely on the behaviour your implementation uses is to rely on the ABI of the targeted architecture, rather than the standard (BAD). Thus, it could result in 'corruption'.

The size of the structure can vary by ABI, and the size of ints and even their byte order could vary -- resulting in 'corruption'. Padding and alignment is also specified by an ABI.

So fixed width types, explicit endianness, and field by field symmetric serialization will often be what you need.

OTHER TIPS

Yes, your code could result in invalid values being read in, due to possible padding between struct fields. Let's use the example of your struct StructOfInts, and imagine that the compiler inserts some padding between the fields, like so:

byte  | 0 1 2 3 | 4 5     | 6 7 8 9 | 10 11 12 13
value | field a | padding | field b | field c

Then when you write the struct to the stream, you could end up with something like

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'

if the fields contained (respectively) the values (int)'a', (int)'b', (int)'c'.

Then when you read the values back in, it would look like

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

which is obviously not what you want.

After searching around about #pragma pack, it looks like it would help with this case. The compiler would not insert padding (although it is implementation defined...), so the values would (most likely) be read and written correctly.

Also, another thing: if you do the writing on one system (computer/OS/compiler) and then read the data in another system, then endianness issues could cause problems as well.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top