Thread: Can someone verify I am using Bitfields, Structures, and Unions together correctly?

  1. #1
    Registered User
    Join Date
    Nov 2018
    Posts
    5

    Can someone verify I am using Bitfields, Structures, and Unions together correctly?

    Main questions on the very bottom if not up for reading everything.

    So a few years ago I tackled my first programming project, googling literally everything as I'm writing the code, learning to code by coding. As you can imagine, I made a few mistakes. What I was doing is transcribing the MDB protocol (vending machine language) into a c program so I could interface an Arduino with one. Well, this turned into like 1 or 2 thousand lines of code (still not even a quarter done!), and years later, I need this code again, I intend to tidy it up, and finish it. I'm still a C newbie, but have actually fully read a C tutorial, now just need hands on experience to burn it all into my brain.

    Here's the first few lines of my code, an important part that acts as a middle man between the code and the UART buffer, allowing me to easily access the 9th bit and the 8 data bits separately. Additionally, I was attempting to create a shortcut for accessing 3 specific data bits, which makes things easier and more readable later in the code.

    Code:
    union nineBit {                       //Union allows writing mode and data bits simultaneously as a short, therefore not overwriting one another.  Bit format: dddddddd_______m
        struct {                          //Structure allows accessing 8 data bits and 1 mode bit separately, as well as setting the parent union's size.
            unsigned char data : 8;       //8 data bits dddddddd most significant byte when written to as a short..
            unsigned char mode : 1;       //1 mode bit  _______m least significant byte when written to as a short.
        } part;                           //Named for readability & organization of code.
        unsigned short whole;               //Allows writing the 'data' and 'mode' all at once, otherwise the second write would erase the first.
        unsigned char command : 3;        //The three bits containing a command in an address byte.  mdddddccc. 
    } block[35];                          //Array of 9 bit data, 36 is the maximum amount of 'bytes' MDB allows per transmission.
    Given the short datatype, let each number represent a bit's location.
    01234567 89ABCDEF

    Goals:
    I want to write to block[0].whole when interacting with the UART buffer. It should write the 9 bits of data in 0-7 and F, not 7-F. This seems wrong, but I do remember this code working, so reading 9 bit data from the UART buffer, if I remember right, you read it as two separate characters, which makes it easy to flip the mode bit around if needed then write the two bytes as a short. So I think this is good.

    I want to read from block[0].data and have it give me bits 0-7, not 8-F. This seems to be correct.

    I want to read from block[0].mode and have it give me bit F. This seems to be correct.

    I want to read from block[0].command and have it give me bits 0-2, however this doesn't seem like it'd work at all, and I think I remember it being an issue trying to use it. How can I fix this? Can I change it to a short and somehow flip the endianness? Can I do some pointer magic somehow?

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    38,710
    > How can I fix this?
    You can't.

    > Can I change it to a short and somehow flip the endianness?
    No.

    > Can I do some pointer magic somehow?
    No.

    The problem is that bit-fields are just the wrong tool for the job.

    Almost everything about bit-fields is implementation specific, which makes them useless for trying to pick apart external data packets.
    Code:
    struct foo {
        int a : 3;
    };
    There is no way to tell in advance whether you end up with
    xxxxxaaa
    aaaxxxxx
    xx..xxaaa (16 or 32 bits)
    aaaxx..xx (16 or 32 bits)

    That is, you can't portably control whether bits are allocated lsb-first, or msb-first, nor what is chosen as the underlying storage unit (whether byte, short or int).

    Sure, in this simple example, most things would choose a 'byte', but you still in the dark over which end of the byte the 3 bits of interest are.

    You might eventually discover some bit-field declaration that works for you, but it will be unbelievably fragile. Any change (edit the structure, change compiler flags, patch/update the compiler, change the compiler) risks disaster.


    Your only reliable and portable way to go is along the lines of
    Code:
    typedef struct nineBit {
        unsigned char data;
        unsigned char mode;
    } nineBit;
    
    // encapsulate the UART accesses here
    void readUart( nineBit *p ) {
    }
    void writeUart( const nineBit *p ) {
    }
    
    // encapsulate the protocol accesses here
    unsigned char getMDBData( const nineBit *p ) {
        // use bitwise operators & | ^ << >> to get the bits of interest
    }
    unsigned char getMDBControl( const nineBit *p ) {
        // use bitwise operators & | ^ << >> to get the bits of interest
    }
    That is, you quickly create a couple of layers of abstraction which first insulate you from the grubby details of interacting with UART's, then insulate you from the grubby details of the MDB protocol.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Structures and unions
    By frktons in forum C Programming
    Replies: 1
    Last Post: 07-30-2010, 08:47 AM
  2. Structures - Unions
    By AProg in forum C Programming
    Replies: 16
    Last Post: 05-27-2003, 12:43 AM
  3. Unions and Structures
    By C-Struggler in forum C Programming
    Replies: 4
    Last Post: 03-06-2003, 11:28 AM
  4. Structures and unions
    By Paninaro in forum C Programming
    Replies: 6
    Last Post: 06-21-2002, 01:35 PM
  5. Structures & Unions
    By Unregistered in forum C Programming
    Replies: 2
    Last Post: 06-20-2002, 03:25 AM

Tags for this Thread