Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nested bitfields in C/C++

Tags:

c++

c

bit-fields

I need to create a structure with bitfields to encapsulate some data coming from hardware. Assuming I use compiler-specific mechanisms to enforce packing and ordering, is it possible to create a structure similar to the following (not syntactically correct):

typedef struct _BYTE_OF_DATA
{
    uint8_t Reserved1 : 2;
    struct
    {
        uint8_t BitWithSomeMeaning : 1;
        uint8_t BitWithSomeOtherMeaning : 1;
    } BitsWithMeaning;
    uint8_t Reserved2 : 4;
} BYTE_OF_DATA, *PBYTE_OF_DATA;

static_assert(sizeof(BYTE_OF_DATA) == 1, "Incorrect size");

Which can then be accessed as follows:

BYTE_OF_DATA byteOfData;

byteOfData.Reserved1 = 1;
byteOfData.BitsWithMeaning.BitWithSomeOtherMeaning = 0;

The exact scheme I have described above will not work, because I guess the struct BitsWithMeaning needs to start at a byte boundary. I was wondering if there is some other trick by which I can achieve this "nesting" of bitfields.

like image 926
TripShock Avatar asked Mar 20 '15 16:03

TripShock


Video Answer


2 Answers

To elaborate on my previous comment something along these lines should allow the access style you desire. Albeit in a far from elegant way:

typedef union _BYTE_OF_DATA {
    struct {
        uint8_t Reserved1 : 2;
        uint8_t : 2;
        uint8_t Reserved2 : 4;
    };
    struct {
        uint8_t : 2;
        uint8_t BitWithSomeMeaning : 1;
        uint8_t BitWithSomeOtherMeaning : 1;
        uint8_t : 4;
    } BitsWithMeaning;
} BYTE_OF_DATA, *PBYTE_OF_DATA;

Personally I would much prefer traditional field mask and position constants and mangle the registers manually. My experience is that accessing volatile I/O bitfields in this style invariably leads to inefficient and race-prone code.

like image 78
doynax Avatar answered Oct 16 '22 12:10

doynax


You should use an union in this case

typedef union _BYTE_OF_DATA {
    uint8_t data;
    struct {
        uint8_t padding1 : 2;
        uint8_t BitWithSomeMeaning : 1;
        uint8_t BitWithSomeOtherMeaning : 1;
        uint8_t padding 2 : 4;
    } BitsWithMeaning;
} BYTE_OF_DATA, *PBYTE_OF_DATA;

static_assert(sizeof(BYTE_OF_DATA) == 1, "Incorrect size");

So you can fill data in one shot :

BYTE_OF_DATA myByte;

myByte.data = someotherbyte;

And get bit with meaning :

int meaning1 = myByte.BitWithSomeMeaning;
int meaning2 = myByte.BitWithSomeOtherMeaning;

Or do the opposite :

myByte.data = 0; // Put all fields to 0

myByte.BitWithSomeMeaning = 1;
myByte.BitWithSomeOtherMeaning = 0;

int data = myByte.data;
like image 26
Bipi Avatar answered Oct 16 '22 14:10

Bipi