3

Having a piece of code like the following:

typedef union
{
    struct bits
    {
        uint32_t bit0 : 1;
        uint32_t bit1 : 1;
        uint32_t bit2 : 1;
        ...
        ...
        uint32_t bit14 : 1;
    }

    uint32_t value;

} MyUnion;

It's important to prevent the compiler from reordering the bitfields since, otherwise, the value of value will change depending on the platform and, possibly, even the size of the compiled binary.

Is there any way to tell the compiler "do not re-order this fields"?

Would declaring variables of type MyUnion as volatile achieve this?

If the union is packed and aligned(4), is it possible to assure that the bitfields won't be reordered, if you are 100% sure that you will be always working with 32 bits platforms, with the same endianness?

EDIT

Can the above be done for only one specific compiler? That is, if being compatible across different compilers is not necessary.

Dan
  • 2,452
  • 20
  • 45
  • Nothing prevents the `value` from changing even without reordering. – Dan M. Aug 07 '19 at 11:03
  • The short answer is: no there isn't. – Sam Varshavchik Aug 07 '19 at 11:04
  • Possible duplicate of [C/C++: Force Bit Field Order and Alignment](https://stackoverflow.com/questions/1490092/c-c-force-bit-field-order-and-alignment) – Dan M. Aug 07 '19 at 11:04
  • 1
    Yeah, it is not possible. But if you always use 32bit platforms with the same endianess, bit order should not change. I found a good article about bitfields http://jkz.wtf/bit-field-packing-in-gcc-and-clang – Cactus'as Aug 07 '19 at 11:06
  • 5
    If you need to force the exact order and arrangement of bits, bitfields are not the right tool for the job. You can spend time tinkering, and you can try using various compiler extensions, but in the end you'll still be unsure and without guarantees, and it will be (in my opinion) way more trouble than it's worth. Instead, if you need to force the exact order and arrangement of bits, just bite the bullet and use `unsigned int` along with some explicit masking and shifting techniques. Bitfields are enticing, but then, so is [pyrite](https://en.wikipedia.org/wiki/Fool's_gold). – Steve Summit Aug 07 '19 at 11:06
  • @DanM. That question doesn't speak about `union`, that is the specific case I'm concerned about. Maybe that can be inferred from that question, but I would like a clear and direct answer for this particular case so I'm sure that I'm not deducing the wrong stuff. – Dan Aug 07 '19 at 11:09
  • Be aware that C and C++ differ in allowing type punning via unions: C does allow it, in C++ it is undefined behaviour! – Aconcagua Aug 07 '19 at 11:14
  • Just don't use bitfields and all the head ache will go away. They are superfluous and dangerous, with no benefits. – Lundin Aug 07 '19 at 11:45
  • 1
    @Dan The containing `union` does not have any effect on the order of the bitfields in the contained `struct`. The direction in which bitfields are allocated within their underlying storage units (`uint32_t` in your case) is implementation defined. – Ian Abbott Aug 07 '19 at 11:46
  • Do you actually know a compiler that "reorders" the bitfields, even without pack/volatile/whatever? – Marc Glisse Aug 08 '19 at 16:10

1 Answers1

4

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.

Joel Bodenmann
  • 2,152
  • 2
  • 17
  • 44
  • `can't declare a union as volatile` - what do you mean by that? A variable that has the type union can be volatile. A typedef can be an union and volatile. I think you will be surprised that you can include `volatile` and ex. `const` in a typedef, like `typedef union { int a; } volatile MyUnion;`. – KamilCuk Aug 07 '19 at 11:14
  • Yes, you are right, a type declaration (in this case `union`) cannot be volatile of course. But I meant variables of type `MyUnion` (I wrote it wrong), not the `union` itself. Now it's fixed. – Dan Aug 07 '19 at 11:31
  • Unions can be declared volatile. `typedef union foo { int x; float y; } Foo; typedef volatile Foo VolatileFoo;` is valid C code that defines `VolatileFoo` to be a type that is a volatile union. Furthermore, after these statements, `Foo Convert(VolatileFoo *x) { return x; }` yields a compiler message that types are incompatible, showing the compiler knows that `x` points to a volatile union, not just a union, thus demonstrating that `volatile` is a part of the type `VolatileFoo`. – Eric Postpischil Aug 07 '19 at 11:39