Take the 2-minute tour ×

Let's say I have data, such as below:

    char flags : 4;
    uint16_t   : 12;
  char data[2];

I understand how to make this code run regardless of byte endianness on a platform. I am asking to be sure that my understanding of how it would be stored on the different endians is correct.

As I understand it: If I were to store a uint16 in the 12 bit uint, both endians would drop the 4 highest bits. Big-endian would store the remaining 4 high bits in the same byte as the flags, and the rest in a separate byte. Little-endian would store the 4 lowest bits in the same byte as the flags, and the rest in a separate byte.

Is this right?

share|improve this question
the C++ specs are trying to define and provide a logically correct language, not a language that is correct to the bit ; if this makes some sort of sense to you. In other words, C++ doesn't care nor specifies the representation of the information used at the bit level, this is a similar issue to the reason why you can't infer a float as a template argument, C++ doesn't provide a definition for the representation of float so it can't even offer some basic guarantees that are essential for templates. Everything about this is compiler and ABI specific. –  user2485710 Mar 5 at 7:00

1 Answer 1

up vote 1 down vote accepted

It depends on the compiler and the target platform's ABI. See, e.g. the rules for GCC bit-fields: The order of allocation of bit-fields within a unit is Determined by ABI. Also each field is supposed to be declared int or unsigned int, not uint16_t.

If you want to control the data format, you can use shifting and masking to assemble the data into a uint16_t. If your aim is to write the data out in a well-defined format, you can write the uint16_t bytes in the required endianness or just assemble the data into 2 bytes and write them in the required order.

Unless you find language spec docs that promise what you want, or your compiler docs make clear promises and you're using the same compiler for big and little endian CPUs, don't rely on C/C++ compilers to all do something like this the same way.

share|improve this answer
So it is not only determined by the platform, but the compiler you use as well? Thinking about it now, I remember uint16_t is not defined as a base type, it's declared in a separate header. It would make sense that a bit-field should only support the base types. My original hope was that I could include an 'endianness' field in each message, and if the host had the same endianness as the messages' sender, then I could skip the bit shifting and load the raw data into a union like above. I see this will not work. –  Andrew Mar 5 at 18:43
The padding between fields can also vary by compiler and target platform. The usual approach is to always send data in "network byte order" (which is big endian). See XDR for an example standard. There are libraries to help do this. –  Jerry101 Mar 5 at 19:37
Thank you for all your help. I understand how to make this endian agnostic, I'm just looking for tiny optimizations - out of personal interest. There is no way I will write code dependant on something so finicky as this. Apparently padding is almost always non-existent for byte size data. Upvoting your answer because you have been incredibly helpful. –  Andrew Mar 5 at 20:17
Glad to help, @Andrew –  Jerry101 Mar 6 at 2:40

Your Answer


