If I use sizeof() for a binary read/write of an enumerated type variable, is this going to cause me problems with cross-platform compatibility? Specifically, does GCC implement this consistently on different platforms?
P.S. I am fully aware that I could cast the variable as an integer, but I'm doing a lazy IO like this:
fwrite(reinterpret_cast<char*>(this), sizeof(struct));
Which writes the struct as a single binary chunk.
You should never, EVER fwrite a struct to begin with.
Right. Always do it member by member.
That still doesn't solve his enum problem, and no, it will not be done the same way on all systems, perhaps. GCC might do it the same way though. The Win32 API's enums have a FORCE_DWORD enum, and they define it like so:
enum MyEnum { value = 0, value2 = 1, //etc FORCE_DWORD = 0xFFFFFFFF };
Or something like that. That would make sure it is DWORD-sized or bigger I'd think, and not the size of a DWORD.
Really you can't rely on sizeof(int) being the same and such. This is one of the things that suck about C++. You could try using some of the C99 types if your compiler supports them (I think Boost provides a wrapper for compilers that don't support it). And I believe some of the C99 types guarantee a variable of an exact size.
Johan peitz fwrites structs, and spellcaster considers fwriting structs a coding gem.
Boost has int<num_of_bits>_t types which provide cross-platform sizes and there's some header for C, maybe stdint.h, can't remember.
why do you say to not fwrite a struct?
i think that its one of the fastest way to write down a complicated data sequence
Both Peitz and Lenny are wrong here, I'd say. 
And as for your reasons why you would not want to ... every compiler and platform might use different schemes for 1) Endianness 2) Struct padding/alignment 3) Type sizes, and thus you can't guarantee that fwritten struct data will be compatible across compilers/platforms.
If you try compiling your program with another compiler (or different version of your current compiler), you'd better hope and pray those variables are the same size, use the same padding, etc. Otherwise, you're boned. Member by member is much safer. Slower, but safer.
Johan peitz fwrites structs, and spellcaster considers fwriting structs a coding gem.
Wirting structs to disk isn't disallowed, or illegal, or undefined. It's usually bad practice because most people doing it aren't aware of the consequences.
If you read/write structs to disk, you can no longer:
- Change compiler options
- Change compiler
- Change the struct or class in any way.
- Use pointers in that struct/class
- Use inheritence on that struct/class
- Use polymorphism on that struct/class
- Port files to other platforms.
Of course, if you can live with those restraints, then writing a struct/class to a file may be a good idea.
It is the fastest way to write down a complicated structure. Sometimes it's also the only practical way to do so.
It happens to also be really nasty in C / C++:
a. The sizes of primitive items within a struct vary depending upon your platform, so files produced this way can't be shared across platform boundaries
b. On some platforms the compiler may add invisible "padding" bytes to your structures... this can reduce efficiency, and result in a lack or portability similar to sizes of primitives issue.
c. There tends to be endianness portability issues if you use any primitives larger than 1 byte.
d. If your struct contains pointers... well... you'll have to handle that specially of course.
e. If you're using C++ and your struct has a virtual method or somesuch, then the type data (vtable pointer) will be included as well, but it may result in nasty nasty stuff: the correct value might not even be portable between different runs on the same computer using the same compiler.
All that said, if you insulate your types by defining intermediates ala SDLs Uint32, C99s uint32_t or whatever, and you're carefully about alignment issues, and you don't use anything virtual, and you handle the endianness issues somehow, it IS possible to write fairly portable code that does raw fwrites with structs.
Thanks for the input guys. Currently my game architecture uses C++ style classes with parallel packed c style structs for IO. This design works really well in combination with overloaded assignment operators. But as was pointed out, be careful:)
I forgot that endian issues may effect enums (if they're stored and presumably written as DWORDs), so perhaps I had best convert my enums to int64s. I don't like doing 200 casts, but if I don't it will probably come back to haunt me sometime. BTW, thanks Gillus for the Boost C99 types wrapper idea. I'll definitely look into using those.
I don't know why you would cast to 64-bit integers. That's pretty excessive for an enum. Depending on your enum you should be able to cast to unsigned char or unsigned short?
I forgot that endian issues may effect enums (if they're stored and presumably written as DWORDs), so perhaps I had best convert my enums to int64s.
Which, apart from the insane memory usage, will not solve your endianesse problem.
Use Allegro's packfile functions for writing portable files (because you need to specify endianesse anyway).