Sign in to follow this  

Any portable/semi-portable way of forcing class field order in C++?

This topic is 676 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

To be honest, my overall knowledge when it comes to the neurotic moodscape of various compilers is largely lacking. I've pretty much exclusively used VS thus far and barring a few quirks it's been pretty nice to me. Now, as I'm in the process of reorganizing large chunks of my entire codebase, however, I'd like to deal with some potentially less upfront portability issues. Basically, I have a handful of structures whose data fields are read directly from disk in chunks and to bypass serialization I want those to retain their field ordering under all circumstances for a given endianess. So far Googling has led me to the notion that it's, to quote StackOverflow, "a bit of a nightmare".

 

Is there a remotely portable way to enforce this? What compiler directives should I be looking at? My current target is Windows, but I'm taking considerable care with respect to dependencies to keep my code portable to Linux and OSX at some point. As far endianess goes, I want to maintain code integrity as is, but rebuild source data as needed.

Share this post


Link to post
Share on other sites
I'm not aware of any compilers reordering data members. The standard does not promise much about member data, but I'm pretty sure it promises sequence. What it very specifically does not promise is padding (that is, how many 'dead bytes' are added between members to make them align nicely on the target platform).

If you have to serialize whole structures (what is in my opinion not a good idea), at least static_assert the size you expect to see. If a compiler tries anything cute regarding padding at least it will quickly and obviously blow up. Unless the compiler adds different padding but ends up at the same total size. In that case, have fun.

Share this post


Link to post
Share on other sites

Just one thing that wasn't mentioned yet: in C++, "public:" / "private:" / "protected:" labels define different blocks of variables. Within these blocks, the order is preserved, however the standard doesn't guarantee that block order will be preserved. I've no idea how often reordering is the case in practice, though simply using structs / making all members of a class public will guarantee that there are no ordering issues.

Share this post


Link to post
Share on other sites

So far Googling has led me to the notion that it's, to quote StackOverflow, "a bit of a nightmare".

The SO ivory tower is a tad different to the real world.
I've seen this type of code, working easily, in almost every game I've worked on and make extensive use of it on my current projects. Just make it a POD struct full of public (default) members, use fixed-size types, and be aware of padding/alignment rules.
Like LS, I use static assertions on the size to catch stupid errors, and static assertions on the offsets if I'm being really careful.
On all the platforms/compilers that you care about, the padding/alignment rules will almost certainly be predictable, fairly sane, and reliable enough to write this kind of code without even having to worry about portability issues.

Biggest portability issue that I have is sometimes I have a pointer field in these structs -- or an integer 'offset' that is converted into a real pointer on load. This creates two different versions of the struct for 32/64bit platforms, which sometimes is fine if you're building the data per platform (just be sure to use a pointer-sized integer), or alternatively I have a typedef for a "cross-platform pointer sized integer", which is basically uint64_t laugh.png

Edited by Hodgman

Share this post


Link to post
Share on other sites

Third-ing. That is my experience as well.

 

I wouldn't call their world an "ivory tower" of academia that is not the real world. There are real-world projects where you do need to support all the devices on all the systems.  For example, if you're working on the Boost project or other widespread multi-system library.

 

But that is not games.  Games only hit a handful of systems and compilers, as LSpiro covered so nicely.  The effort required is minimal.  Normally everything works the first time, and the rare times it doesn't, the fix is not difficult.

Share this post


Link to post
Share on other sites

This topic is 676 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this