swinchen
swinchen

Reputation: 41

Forcing alignment of C bitfield using a union

I was wondering if it is possible to force the alignment of bitfield in C. Using the variables in the code below I know that writing to _align_bytes then reading from bits is undefined (and vice-versa) because it is implementation depended. Is the code below a valid method to "persuade" bits to be stored contiguously in something that is the size of unsigned short? I believe that (minus any endian issues) this code is correct... but bitfields and unions are the two C topics I am least familiar with.

I am doing a low level micro-controller project and would like an easy method of reading configuration bits without a ton of bit masking. Thanks for any tips and suggestions.

Sam

P.S. Please disregard any assumptions I make about endianness as this project I am working on is very low level and not intended to be ported to other devices/platforms.

#include <stdio.h>
#include <assert.h>

typedef union packet {
    struct {
        unsigned int bit0  : 1;
        unsigned int bit1  : 1;
        unsigned int bit2  : 1;
        unsigned int bit3  : 1;
        unsigned int bit4  : 1;
        unsigned int bit5  : 1;
        unsigned int bit6  : 1;
        unsigned int bit7  : 1;
        unsigned int bit8  : 1;
        unsigned int bit9  : 1;
        unsigned int bit10 : 1;
        unsigned int bit11 : 1;
        unsigned int bit12 : 1;
        unsigned int bit13 : 1;
        unsigned int bit14 : 1;
        unsigned int bit15 : 1;
    } bits;

    unsigned short _align_bytes;
} packet_t;

int main(int argc, char *argv[]) {

    assert(sizeof(unsigned short) == 2);

    unsigned short data = 0xA05F;
    packet_t *p = (packet_t *)&data;

    printf("%u", p->bits.bit15);
    printf("%u", p->bits.bit14);
    printf("%u", p->bits.bit13);
    printf("%u", p->bits.bit12);
    printf("%u", p->bits.bit11);
    printf("%u", p->bits.bit10);
    printf("%u", p->bits.bit9);
    printf("%u", p->bits.bit8);
    printf("%u", p->bits.bit7);
    printf("%u", p->bits.bit6);
    printf("%u", p->bits.bit5);
    printf("%u", p->bits.bit4);
    printf("%u", p->bits.bit3);
    printf("%u", p->bits.bit2);
    printf("%u", p->bits.bit1);
    printf("%u", p->bits.bit0);

    return 0;
}

Upvotes: 2

Views: 3952

Answers (2)

X-Istence
X-Istence

Reputation: 16667

I am not sure, but wouldn't this violate strict aliasing rules because two pointers of different types are pointing to the same memory location? In C89 and C99 you are not guaranteed to get anything back correctly.

You may want to test this, and if required use -fno-strict-aliasing or something similar for your compiler so that it disables strict aliasing which could cause issues.

Upvotes: 0

brianmearns
brianmearns

Reputation: 9967

This is a common pattern and as far as I know, the answer is yes: the bit fields will be contiguous and occupy the same memory as the _align_bytes field. That's the whole point of a union, right? Different ways of looking at the same memory.

I'm not sure what you mean by "writing to _align_bytes then reading from bits is undefined". The only issue I see is the endianess: bit0 may be the lsb or the msb of _align_bytes. If you don't want it to be portable, then you just need to do a quick test to figure out which it is, and you should be set.

Upvotes: 3

Related Questions