2

I have the following issue using an ARM® Cortex™-M4F CPU running mbedOS 5.9.

Say I have the binary value 10101000 and that I also have the following union/struct:

union InputWord_u
    {
        uint8_t all;

        struct BitField_s
        {
            uint8_t start   : 1; // D7
            uint8_t select  : 3; // D6, D5, D4
            uint8_t payload : 4; // D3, D2, D1, D0
        } bits;
    };

I have a simple program where I access my word and assign the values as such:

InputWord_u word;
word.bits.start = 0b1;
word.bits.select = 0b010;
word.bits.payload = 0b1000;

Therefore, word.all == 10101000 and is a uint8_t.

If I print this as such printf("%u", word.all); then I receive the value of 133.

If I then define the following uint8_t:

uint8_t value = 0b10101000;

And print this using printf("%u", value); then I receive the value 168.

I expect both values to equal 168.

I appreciate that this is likely me grossly misunderstanding how a Struct is represented in memory. Nevertheless, could someone please explain what is exactly going on?

Thanks.

amitchone
  • 1,630
  • 3
  • 21
  • 45
  • 1
    What's the endianness on your system? I recommend examining the actual bit values of both variables and comparing/analysing them. – Lightness Races in Orbit Oct 10 '18 at 09:56
  • I believe it's little-endian. It's an ARM® Cortex™-M4F CPU running mbedOS. – amitchone Oct 10 '18 at 09:58
  • Actually I just realised endianness probably doesn't come into it, sorry. Still, bit compare... – Lightness Races in Orbit Oct 10 '18 at 09:59
  • 2
    Have you read back each bitfield as well, and printed them? Have you printed the intermediate values of `all` as you assign the bitfields? Have you assigned your expected value to `all` and then read out the value of each bitfield for comparison? – Useless Oct 10 '18 at 10:04
  • @Useless That's a useful suggestion, I'll do that and see what we get. Cheers. – amitchone Oct 10 '18 at 10:05
  • If there is any padding in there, you should be able to tell by checking whether `sizeof(InputWord_u) > sizeof(uint8_t)` – Useless Oct 10 '18 at 10:07
  • They're both 1 byte in size and, if I assign `word.all = 0b10101000` then it prints 168. Time to read back the bitfields and see what's going on... – amitchone Oct 10 '18 at 10:10
  • 1
    Note that this way of working with unions has undefined behavior in C++ (but not in C): see [Accessing inactive union member and undefined behavior?](https://stackoverflow.com/q/11373203/673852). – Ruslan Oct 10 '18 at 10:10

3 Answers3

4

The standard guarantees hardly anything about the representation of bit-fields.

Therefore, word.all == 10101000

What you've tripped over here is that you've assumed that the bit-fields are packed starting from most significant bit to least significant.

However, it appears that your bit fields were stored in the reverse order, and in fact word.all == 1000'010'1. To get the result you expect, you could reorder the bit-fields:

struct BitField_s
{
    uint8_t payload : 4; // D3, D2, D1, D0
    uint8_t select  : 3; // D6, D5, D4
    uint8_t start   : 1; // D7
} bits;

But be aware that bit-fieds are not portable: Other systems might not have the same order.

eerorika
  • 232,697
  • 12
  • 197
  • 326
3

The problem is, you calculated value in reversed way, like

(start << 7) | (select << 4) | payload

And actual value is calculated like

(payload << 4) | (select << 1) | start

So your bitfield starts with less-significant parts of uint8. It has nothing to do with little-endianness of system, because little-endianness defines orders of bytes in uint16, uint32 e.t.c.

Order of bits of bitfield inside byte is defined by compiler. For example, MSVC uses low-to-high order, as in your example.

V. Kravchenko
  • 1,859
  • 10
  • 12
2

Binary value of 133 and 168

133 = 10000101
168 = 10101000

sums it that actual alignment is different from your assumed alignment.

It seems that it as arranging in the following manner:

----     ---     -
         all
payload  select  start

And you are assuming the following order

-     ---  ----
start all  payload

I also think different compiler has different alignment.

doptimusprime
  • 9,115
  • 6
  • 52
  • 90