A6SE
A6SE

Reputation: 177

Accessing individual bits of unsigned integer through pointer to struct with bit fields in C

Let's say we have a struct defined like:

struct S_BF {
    unsigned first_bit : 1;
    unsigned second_bit : 1;
    unsigned rest : 30;
}

And a pointer to S_BF struct:

struct S_BF*  bf;

If we have a variable:

unsigned int p = 0;

How can we make bf point to p so we can modify the value of p by modifying its bit fields, for example, if we want to change the value of p to 2, we can do this:

bf->second_bit = 1;

Upvotes: 1

Views: 573

Answers (1)

David C. Rankin
David C. Rankin

Reputation: 84607

The problem with wanting to access the bits of unsigned p with a pointer of type struct S_BF* is that it violates the strict alias rule C11 Standard - §6.5 Expressions (p6,7). The rule is designed to prevent accessing an object of one type by using a pointer to another. (there are various exceptions, but the intent of the rule is to prevent the type-punning of pointers)

The only standard conforming way to access the bits of an unsigned through a pointer to struct S_BF it to make the bits the same bits through a union between struct S_BF and unsigned. You must can access the bits of struct S_BF through a pointer to struct S_BF, and make the struct S_BF and unsigned the same through the union without violating the string aliasing rule. A short example would be:

#include <stdio.h>

struct S_BF {               /* bitfield struct */
    unsigned first_bit : 1;
    unsigned second_bit : 1;
    unsigned rest : 30;
};

union s2u {                 /* union bitfield struct/unsigned */
    struct S_BF s;
    unsigned u;
};

int main (void) {

    union s2u s2u = { .u = 0 };             /* union initialized zero */
    struct S_BF *bf = &s2u.s;               /* pointer to bitfield */
    unsigned sz = 32;                       /* no. of bits in unsigned */

    bf->second_bit = 1;         /* set second bit 1 */
    bf->rest = 0x2aaaaaaa;      /* alternating bits 1010101... */

    while (sz--)    /* loop sz times, using unsigned value in union */
        putchar (s2u.u >> sz & 1 ? '1' : '0');  /* output bits */

    putchar ('\n');
}

Example Use/Output

The above example would result in the following output:

$ ./bin/bitfield_union
10101010101010101010101010101010

Upvotes: 1

Related Questions