Declaring Structures, Trick #2

In last week’s Lesson, I covered a trick you can use to assign values to structure members non-sequentially. It’s something you may rarely use, but a valid tool in your C programming tool chest. It’s also not the weirdest thing that can happen in a structure.

In C, structures and unions can hold integer values of defined bit widths. So instead of holding 32 bits, you can define an int structure member that holds only 4 bits.

Weird.

This capability is something I’ve never seen used and is perhaps one of the most unusual aspects of C. It’s unique to structures and unions, though I’m not a fan of unions as undefined memory space is a risky thing to have in your program. With a structure, however, you can declare an integer member and limit its values to a specific bit field:

struct bitfield {
    int b:4;
};

The structure above contains a single member, integer b, which is limited to 4 bits of data. The format for such a bit-field integer structure member is the variable name, a colon, and the bit width. The bit width range must be between one and the number bits in the data type, 32 for an int.

The bitfield structure in the following code, contains a single member, b, an int value limited to 4 bits. Because it’s a signed integer, valued values for bits.b range from -8 through 7.

2021_11_06-Lesson-a.c

#include <stdio.h>

int main()
{
    struct bitfield {
        int b:4;
    };
    struct bitfield bits;

    bits.b = 5;

    printf("bits.b = %d\n",bits.b);

    return(0);
}

Here is the output:

bits.b = 5

You can specify an out-of-range value for the bit field structure member, just as you can do so for any data type:

bits.b = 100;

Here is the warning generated if you attempt such an assignment:

warning: implicit truncation from 'int' to bit-field changes value from 100 to 4

The hex value of 100 is 0x64. If you limit it to the first four bits, you get 0x4, which is what the error message explains. Run the code and the output confirms the truncating:

bits.b = 4

Also curious to me is if you change the printf() placeholder to %X, you see unusual output for negative values. If I change the value of member bits.b to -8, here is the output:

bits.b = FFFFFFF8

The value of 0xFFFFFFF8 is -8, but it shows all the bits in the full integer. So internally, the program is most likely dealing with a full 32-bit int value. The truncation happens when the program handles the data. Also, if you’re going to mess with all the bits in a limited bit field, it’s best to declare the variable as unsigned:

2021_11_06-Lesson-b.c

#include <stdio.h>

int main()
{
    struct bitfield {
        unsigned b:4;
    };
    struct bitfield bits;

    for( bits.b=0x0; bits.b<=0xF; bits.b++ )
        printf("bits.b = %X\n",bits.b);

    return(0);
}

This code attempts to loop from hex values 0x0 through 0x0F, the full width of unsigned structure member bits.b‘s values. Here is the output:

bits.b = 1
bits.b = 2
bits.b = 3
bits.b = 4
bits.b = 5
bits.b = 6
bits.b = 7
bits.b = 8
bits.b = 9
bits.b = A
bits.b = B
bits.b = C
bits.b = D
bits.b = E
bits.b = F
...∞

As with any data type, when the value of bits.b is incremented one last time in the for loop, it wraps back to zero, which leads to an infinite loop. The solution is to increase the bit field size at Line 6:

unsigned b:5;

The loop now runs once.

In next week’s Lesson, I continue exploration of this weirdo bit fields feature available in C language structures.

2 thoughts on “Declaring Structures, Trick #2

  1. Dan, in the past, I was taught when using C that if I wanted my code to be as portable as possible, which I did, I needed to address alignment in my structs required by RISC CPU architectures although it is not required with Intel CPUs. Accordingly, within a structure, numeric data types should go first being sure the numeric elements align on 4 byte boundaries. If not, padding should be added before adding the non-numeric fields.

    Was that your understanding, and is it still the case? For example, I would do it like this:

    struct
    {
         short a;
         short b;
         short C;
         short pad_1;       // padding to end numeric section on  4 byte boundary
         mytext[101);
    } mystrc;

    Thanks for the great blog and your answer, if this makes the cut.
    Regards
    Danny

  2. Danny, you can still perform this trick in C. I cover alignment in structures in tomorrow’s (11/13) blog post. It has an interesting, oddball shortcut that lines up structure members, including partial bytes.

Leave a Reply