I have a struct with three variables: two unsigned ints and an unsigned char. From my understanding, a c++ char is always 1 byte regardless of what operating system it is on. The same can't be said for other开发者_开发知识库 datatypes. I am looking for a way to normalize POD's so that when saved into a binary file, the resulting file is readable on any operating system that the code is compiled for.
I changed my struct to use a 1-byte alignment by adding #pragma
as follows:
#pragma pack(push, 1)
struct test
{
int a;
}
#pragma pack(pop)
but that doesn't necessarily mean that int a
is exactly 4 bytes on every os, I don't think? Is there a way to ensure that a file saved from my code will always be readable?
You can find fixed-width integer types (like std::int32_t
and std::uint16_t
) in <cstdint>
. Your C++ Standard Library implementation may not include <cstdint>
(it's not part of the current C++ standard; it's part of C++0x), in which case Boost has an implementation that should work on most platforms.
Note that you will still have to think about endianness and alignment, among other things. If your code needs to run on platforms with different numeric representations (e.g. one's complement and two's complement), you'll need to consider that too.
If you are concerned with 32-bit Windows, 64-bit Windows, Linux (x86 and AMD64) and Mac (x86, AMD64, PPC), then it's more easy. An int will always be 32 bits on all of these systems. If you can allow to drop PPC, it will also be little-endian always. If you need to support big-endian systems, I recommend to store data in network byte order, using ntohl/htonl.
There's no way to just write a binary struct out like that and have it readable by any system. While you can use some library that defines types like int32
, that doesn't solve your problem.
Different processors use different byte orders, and may require different alignment. Further, padding is implementation-dependent. Fortunately, all current processors I'm aware of use twos-complement for integer representation rather than ones-complement or sign-magnitude, so integers at least have the same binary representation (modulo byte order).
No #pragma
can be a truly portable solution, since they're by definition implementation-defined, and you can't be certain that different compilers will treat them the same. There are some more specifiers being worked on for the next C++ standard, but they're not going to be all that common for some time.
What you are going to have to do is specify the struct
with something like int32
, and then break it down into a stream of bytes and build it back up again on the other end. Look up "serialization".
The proper way to do this is to serialise the data in a standard format. There are many standards out there for doing this. For simplicity CSV is one (comma separated variables). If you want a more efficient standard, try XDR, or, one used in the telco industry a lot, ASN.1.
精彩评论