C/C++: Force Bit Field Order and Alignment

C/C++: Force Bit Field Order and Alignment

No, it will not be fully-portable. Packing options for structs are extensions, and are themselves not fully portable. In addition to that, C99 §6.7.2.1, paragraph 10 says: "The order of allocation of bit-fields within a unit (high-order to low-order or low-order to high-order) is implementation-defined."

Even a single compiler might lay the bit field out differently depending on the endianness of the target platform, for example.

Order of fields when using a bit field in C

C standard allows compiler to put bit-fields in any order. There is no reliable and portable way to determine the order.

If you need to know the exact bit positions, it is better use plain unsigned variable and bit masking.

Here's one possible alternative to using bit-fields:

#include <stdio.h>

#define MASK_A 0x00FF
#define MASK_B 0x3F00
#define MASK_C 0xC000
#define SHIFT_A 0
#define SHIFT_B 8
#define SHIFT_C 14

unsigned GetField(unsigned all, unsigned mask, unsigned shift)
{
return (all & mask) >> shift;
}

unsigned SetField(unsigned all, unsigned mask, unsigned shift, unsigned value)
{
return (all & ~mask) | ((value << shift) & mask);
}

unsigned GetA(unsigned all)
{
return GetField(all, MASK_A, SHIFT_A);
}

unsigned SetA(unsigned all, unsigned value)
{
return SetField(all, MASK_A, SHIFT_A, value);
}

/* Similar functions for B and C here */

int main(void)
{
unsigned myABC = 0;
myABC = SetA(myABC, 3);
printf("%u", GetA(myABC)); // Prints 3
}

How to enforce the struct bit order with the GCC compiler?

Which version of GCC are you using and which platform? A pragma exists that may do the trick, but it doesn't work on x86 starting with GCC 4.

#pragma reverse_bitfields on

More details at:

http://groups.google.com/group/gnu.gcc.help/browse_thread/thread/747918655affa5c0?pli=1

If you don't mind rebuilding GCC, all the relevant build settings are here (search for bitfield):

http://gcc.gnu.org/onlinedocs/gccint/Storage-Layout.html

Some details about bitfields being bad:

C/C++: Force Bit Field Order and Alignment

Bit order in struct is not what I would have expected

The worse part is that a different compiler could give the expected order. The standard has never specified the implementation details for bitfields, and specifically the order. The rationale being as usual that it is an implementation detail and that programmers should not rely nor depend on that.

The downside is that it is not possible to use bitfields in cross language programs, and that programmers cannot use bitfields for processing data having well known bitfields (for example in network protocol headers) because it is too complex to make sure how the implementation will process them.

For that reason I have always thought that it was just an unuseable feature and I only use bitmask on unsigned types instead of bitfields. But that last part is no more than my own opinion...

How can I get bitfields to arrange my bits in the right order?

(Note that all of this is gcc-specific commentary - I'm well aware that the layout of bitfields is implementation-defined).

Not on a little-endian machine: The problem is that on a little-endian machine, the most significant bit of the second byte isn't considered "adjacent" to the least significant bits of the first byte.

You can, however, combine the bitfields with the ntohs() function:

union u_Bits2{
struct Bits2 {
uint16_t _padding:7;
uint16_t a:6;
uint16_t b:1;
uint16_t c:1;
uint16_t d:1;
} bits __attribute__((__packed__));
uint16_t word;
}

union u_Bits2 flags;
flags.word = ntohs(flag_bytes_from_network);

However, I strongly recommend you avoid bitfields and instead use shifting and masks.

Bit field extract with struct and endianness in C

Endianness can also affect bits, not just bytes, however the only time you typically see the effects is in a bitfield. This is one reason why the ordering of bitfields in a struct, and which byte offsets they live at, is implementation defined.

Looking at this definition, it seems to imply that for the given implementation that bitfields are physically placed in order on big endian systems and in the reverse order for each byte on a little endian system.

In particular, the first 4 bitfields occupy 8 bits and the next 2 bitfields occupy 8 bits. So in the case of little endian the order of the first 4 bitfields are reversed with each other and the last 2 bitfields are reversed with each other.

Code like this is common in system header files. For example, /usr/include/netinet/in.h on Linux contains the following struct to model an IP header:

struct iphdr
{
#if __BYTE_ORDER == __LITTLE_ENDIAN
unsigned int ihl:4;
unsigned int version:4;
#elif __BYTE_ORDER == __BIG_ENDIAN
unsigned int version:4;
unsigned int ihl:4;
#else
# error "Please fix <bits/endian.h>"
#endif
u_int8_t tos;
u_int16_t tot_len;
u_int16_t id;
u_int16_t frag_off;
u_int8_t ttl;
u_int8_t protocol;
u_int16_t check;
u_int32_t saddr;
u_int32_t daddr;
/*The options start here. */
};

Presumably, the idea is that a buffer containing a raw network packet can use memcpy to copy the bytes into an instance of this struct (or just have a pointer to this struct point to the buffer, if it's aligned correctly) to simplify serialization / deserialization. You'll still need to call the htonx/ntohx family of function to properly read integer fields occupying more than one byte however.

Prevent GCC from reordering bitfields in unions of structs

I think the overall "No" answer has already been given in the comments. With this answer I'd like to address your question about volatile:

Would declaring MyUnion as volatile achieve this?

The volatile keyword will not change anything in behavior that you're looking for here. Also, you can't declare a union as volatile. It's a keyword that's a qualifier for a variable declaration. It tells the compiler that the variable value can change at any time and that therefore the value should always be re-loaded (as in re-read from memory) instead of assuming the value based on previous statements that the compiler saw.
This is used for when a variable value can change by external factors such as when declaring variables that are linked to real, physical values such as registers in a microcontroller.



Related Topics



Leave a reply



Submit