Sign in to follow this  

Portable c++ for binary file loader

This topic is 2587 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

Hi,

to load a binary file I often use code like this

stream.read((char*)&struct, sizeof(Struct));
stream.read((char*)structs, numStructs * sizeof(Struct));

For the data I use this code works for both x86 and x64. Is it true, that this is a mere coincidence and I should read only read one element of the struct at a time and loop for several structs?

Share this post


Link to post
Share on other sites
If the file representation is the same as the struct and the struct is POD then it is defined and a simliar example (though not reading from disk) is given in the standard. Now this does not make it portable, one compiler may add padding where another does not (it is implementation specific) or sizeof(int) maybe 4 and 8 for example. So writing from one and reading from the other can be undefined behaviour.

Share this post


Link to post
Share on other sites
I try to avoid sizeof() issues by using types defined in <cstdint> in such cases. Is this valid?
What about the padding issues? Is the only way to avoid them, to read element for element?
What is recommended in such a scenario?
I started thinking about those things because of this.

Share this post


Link to post
Share on other sites
Size and padding are different issues. Using fixed sized datatypes does not guarantee uniform padding across platforms (or perhaps even for compiler settings for the same platform). Raw binary I/O is inherently non-portable. The size is not your only problem; you have, for example, endianness and complementness. These issues may also be something you need to handle, depending on which platforms you intend to support.

If you only want to support different operating systems on an x86 architecture, then it may be enough to cover size variations only. If you want to extend to other common architectures, then you may need to consider big vs. little endian architectures. And to take it even further, if you intend to support some exotic platforms, perhaps you need to consider one's vs. two's complement signed integers as well. The number of issues grows with the size your intended target platform set.

Basically, you need to define a set rules that describes how to store your values so that you can read them on all intended platforms; size and endianness being the most important. Then make functions for each platform to load entries from binary sources, and read them one by one. Perhaps not the best solution, but it will handle all the cases covered by the rules you define.

Share this post


Link to post
Share on other sites

This topic is 2587 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