简体   繁体   中英

Is there an easy and efficient way to assign the values of bool [8] to std::uint8_t

Consider the follow variables:

std::uint8_t value;

const bool bits[8] = { true, false, false, true,
                       false, false, true, false };

If I was to print out the array of bools to the console

for (int i = 0; i < 7; i++ )
    std::cout << bits[i];

it would give the following output:

10010010

simple enough and straight forward.


What I would like to do is to generate either a constexpr function, a function template, a lambda, or a combination of them that can run either during compile time or runtime depending on the context in which it is being used to where I could take each of these boolean values of 0s and 1s and store them into the variable value above. If the value is known at compile-time then I'd like for this assignment to be resolved. If the value isn't known at compile-time, then the value will be initialized to 0 until it is updated then it would be used in a runtime context.

However, there is one caveat that isn't obvious at first, but by indexing through the array, the 0 th index of the array will be the LSB bit of the value and the 7 th index will be the MSB. So the order of bits that you are seeing printed from the screen would have a hex value of 0x92 but the value to be stored needs to be 01001001 which would have the hex value of 0x49 or 73 in decimal and not 146.

The above are members in a class where one is the data value representation and the array of bools is the bit representation. I have a few constructors where one will set the data or value member directly and the other constructors will set the array of bools, but I need for both of these values to stay concurrent with each other through the life of the class object if one updates the other needs to be changed as well. Also, the array of bools is a member of a non-named union with a nameless struct of 8 individual bools as a single bit within a bit field. The class also has an index operator to access the individual bits as single boolean values of 0s or 1s.


Here is what my class looks like:

constexpr unsigned BIT_WIDTH(const unsigned bits = 8) { return bits; }

struct Register_8 {
    union {
        bool bits_[BIT_WIDTH()];
        struct {
            bool b0 : 1;
            bool b1 : 1;
            bool b2 : 1;
            bool b3 : 1;

            bool b4 : 1;
            bool b5 : 1;
            bool b6 : 1;
            bool b7 : 1;
        };
    };

    std::uint8_t data_;   

    Register_8() : data_{ 0 } {}
    Register_8(std::uint8_t data) : data_{ data } {

    }

    Register_8(const bool bits[BIT_WIDTH()]) {
        for (unsigned i = 0; i < 8; i++)
            bits_[i] = bits[i];
    }

    Register_8(const bool a, const bool b, const bool c, const bool d,
        const bool e, const bool f, const bool g, const bool h) {
        b0 = a; b1 = b, b2 = c, b3 = d;
        b4 = e, b5 = f, b6 = g, b7 = h;
    }

    const std::uint8_t operator[](std::uint8_t idx) {
        // I know there is no bounds checking here, I'll add that later!
        return bits_[idx];
    }
};

So how can I make each of the values in bits[] to be the individual bits of value where bit[0] is the LSB of value ? I would also like to do this in a context where it will not generate any UB! Or does there already exist an algorithm within the STL under c++17 that will do this for me? I don't have a C++20 compiler yet... I've tried including the std::uint8_t within the union but it doesn't work as I would like it too and I wouldn't expect it to work either!

I walked away for a little bit and came back to what I was working on... I think the short break had helped. The suggestion by user Nicol Bolas had also helped by letting me know that I can do it with a constexpr function. Now I don't have to worry about templates or lambdas for this part of the code.

Here is the function that I have came up with that I believe will assign the bits in the appropriate order.

constexpr unsigned BIT_WIDTH(const unsigned bits = CHAR_BIT) { return bits; }

constexpr std::uint8_t byte_from_bools(const bool bits[BIT_WIDTH()]) {
    std::uint8_t ret = 0x00;
    std::uint8_t pos = 0x00;
    for (unsigned i = 0; i < BIT_WIDTH(); i++) {
        ret |= static_cast<std::uint8_t>(bits[i]) << pos++; // << pos--;
    }
    return ret;
}

If there are any kind of optimizations that can be done or any bugs or code smells, please let me know...


Now, it's just a matter of extracting individual bits and assigning them to my bit-field members, and the track when either one changes to make sure both are updated in a concurrent fashion.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM