I came across some code (it's in a library from Microchip) which has a union.
All was good, until I saw it assigned values to different members of the union right after each other. My immediate thought was "They are over writing the same location..." Then I decided to do a test. By every measure I thought I understood, this union should be one byte (8 bits). But it's not... it's 4 bytes.
#pragma pack(1)
typedef union _STATUS
{
BYTE Val;
struct {
unsigned BC8 : 1;
unsigned BC9 : 1;
unsigned BSTALL : 1;
unsigned DTSEN : 1;
unsigned INCDIS : 1;
unsigned KEN : 1;
unsigned DTS : 1;
unsigned UOWN : 1;
};
struct {
unsigned BC8 : 1;
unsigned BC9 : 1;
unsigned PID0 : 1;
unsigned PID1 : 1;
unsigned PID2 : 1;
unsigned PID3 : 1;
unsigned : 1;
unsigned UOWN : 1;
};
struct {
unsigned : 2;
unsigned PID : 4;
unsigned : 2;
};
} STATUS;
void PrintIt() {
printf("Size of UNION is %d \n", sizeof(STATUS));
}
It should be the largest of any member, which each member is only 8 bits.
The code that caught my eye and made me investigate this is:
STAT.BC9 = 0;
STAT.BC8 = 0;
STAT.Val |= byteToSend;
Which the third line merges into the values from the first and second.
So I wanted to test it, it's coming out as 4 bytes, not one. I even tested it in a few different compilers (hence the #pragma usage for MS Visual C).
Each member is exactly 8 bits, and the last two struct overlap to place the PID values in the same memory location. And yet this is 4 bytes every way I use a compiler to evaluate it.
Is there something in the behavior of adding structs to unions?
Any explanation is appreciated.
While not explicitly specified in the C standard, bitfield will typically occupy a unit corresponding to the base type they are declared with.
In this case all of the bitfields are declared as unsigned
. This type is probably 4 bytes on your system so the bitfields occupy a unit of that type.
If you change the types of the fields to unsigned char
or uint8_t
they should take up only one byte. Note that this assumes your compiler allows using these types for bitfields, although most do.
C has the concept of implicit type. So unsigned
will declare an unsigned int
. But it gets weirder. The same goes if you only use const
or static
/auto
.
const x = 5; // Declares a const int variable
static x; // Declares a static int variable
const static unsigned x = 5; // Declares a const static unsigned int variable
What you want is an unsigned char
.
It should be the largest of any member, which each member is only 8 bits.
It should be at least that size. Nothing prevents it from being bigger.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With