Search code examples
c++bitset

Modifying bits in a byte with a class


I want to directly modify a bit in a byte.

In GCC, you can do it as follow:

struct virtualByte {
    unsigned char b0 : 1;
    unsigned char b1 : 1;
    unsigned char b2 : 1;
    unsigned char b3 : 1;
    unsigned char b4 : 1;
    unsigned char b5 : 1;
    unsigned char b6 : 1;
    unsigned char b7 : 1;
} __attribute__((__packed__));

#define sbit(_byte, _pos) (((volatile struct virtualByte *)&_byte)->b ## _pos)

Usage:

unsigned char myByte = 0x00;

#define firstBit sbit(myByte, 0)

firstBit = 1; // Implicit myByte |= 0x01;

To make things neater I want to have class that does this for me. I came up with the following concept:

unsigned char myByteRef = 0x00;

Byte myByte(&myByteRef);

myByte[0] = 1; // Implicit myByteRef |= 0x01;

fprintf(stderr, "%2.2X\n", myByteRef);

But this does not work because in c++ you cannot return a reference to a single bit. Overloading the constructor does not work either.

Is there a possibility to implement such behaviour? The assignment operator should directly modify its underlying byte (not a set of bytes).


Solution

  • Finally came to a solution, many thanks to @doc!

    My solution:

    class Bit {
        private:
            volatile uint8_t    *byte;
            uint8_t             bitPos;
    
        public:
            Bit(void)
            {
            }
    
            void init(volatile uint8_t *const byte, uint8_t const bitPos)
            {
                this->byte      = byte;
                this->bitPos    = (bitPos > 7u ? 7u : bitPos);
            }
    
            void setValue(bool const bitValue)
            {
                if (!this->byte) return;
    
                if (bitValue) {
                    *this->byte |=  (1u << this->bitPos);
                } else {
                    *this->byte &= ~(1u << this->bitPos);
                }
            }
    };
    
    class BitReference {
        private:
            Bit         &ref;
    
        public:
            BitReference(Bit &ref) : ref(ref)
            {
            }
    
            void operator=(bool const bitValue)
            {
                this->ref.setValue(bitValue);
            }
    };
    
    class Byte {
        private:
            Bit         bits[8];
    
        public:
            Byte(volatile uint8_t *const byte)
            {
                for (unsigned i = 0; i < 8; ++i) {
                    this->bits[i].init(byte, i);
                }
            }
    
            /* This did the trick :)! */
            BitReference operator[](size_t index)
            {
                if (index > 7) index = 7;
    
                return BitReference(this->bits[index]);
            }
    };
    

    Usage:

    uint8_t myPort = 0x00;
    
    int main(int const argc, const char **const argv)
    {
        Byte abc(&myPort);
    
        abc[0] = 1;
        abc[1] = 1;
        abc[2] = 1;
        abc[3] = 1;
    
        fprintf(stderr, "%2.2X\n", myPort);
    
        return 0;
    }