Skip to content


C Union, bitfields (aka. what is that colon in the variable name?)

So both are not commonly used features (except in embedded systems development or device drivers). I thought I would write about these two together, as they are related.

Union
An example of a union first

union test
{
    int i;
    char c[4];
}

A union allocates enough memory to hold the largest type in the union, not all of the types (for example if this was a struct then there would be memory allocated to hold a int AND a char[4]). This means that only one of the data types can be assigned, for example is a union of a float and a int you can either use the int or the float but not both (since there is only one memory space allocated).

The usefulness of a union comes in the fact that you can access individual bytes in the allocated storage. For example with the union above, we can set the entire int at once, or we can set each of the byte of the int individually. For example:

#include <stdio.h>

typedef union test
{
    int i;
    char c[4];
} test;

int main()
{
    test t;
    // set a value
    t.i = 2000;
    // print the hex representation of the int
    printf("%08x\n", t.i);
    // set an individual byte of the int using c[4]
    t.c[3] = 0x3F;
    // print the hex representation of the int
    printf("%08x\n", t.i);

    return 0;
}


/* 
Output
000007d0
3f0007d0
*/

The above is very useful when trying to write to memory locations. For example a union of a DWORD could allow you to set a full DWORD at a time, or access individual WORD. A better formatted union could be (as seen on this stackoverflow article):

typedef union
{
    struct {
        unsigned char byte1;
        unsigned char byte2;
        unsigned char byte3;
        unsigned char byte4;
    } bytes;
    unsigned int dword;
} HW_Register;
HW_Register reg;

Bit field
Bit fields only exist in structs and unions, and allow you to specify the # of bits used to represent a integer type (signed/unsigned int, char). This can be useful for example when you are not storing large numbers in int type variables, and want to conserve some space. For example:

struct
{
    int flag;
} t;

Now this uses 4 bytes of memory, but if you are only going to store 0 and 1 in the flag then its going to be wasting a lot of space. Here using the bit field can make your program allocate only what it needs:

struct
{
    int flag:1; // means this will use only 1 bit
} t;

However, do a sizeof(t), and its still 4 bytes. This is due to alignment, and the real saving comes when you have multiple bit fields:

struct
{
    int flag1:1; // means this will use only 1 bit
    int flag2:1;
    int flag3:2;
} t;

The above also uses 4 bytes, but contains 3 flags (where as if you used 3 ints it will be much bigger). Notice that you dont always need to use 1 bit storage as can be seen with flag3. Keep in mind that the compiler does not necessarily warn if you assign a value outside of the range of the bit field. For example t.flag3 = 20 will compile and run, however don’t expect the correct value stored in it.


Concluding thoughts
Combining union and bit fields is a very useful technique for accessing hardware registers. For example (thanks to the same stackoverflow article as above):

typedef union
{
    struct {
        unsigned char b1:1;
        unsigned char b2:1;
        unsigned char b3:1;
        unsigned char b4:1;
        unsigned char reserved:4;
    } bits;
    unsigned char byte;
} HW_RegisterB;
HW_RegisterB reg;

Posted in C/C++. Tagged with , , , , .