Есть ли простой и эффективный способ присвоить значения bool [8] std :: uint8_t - PullRequest
0 голосов
/ 21 марта 2020

Рассмотрим следующие переменные:

std::uint8_t value;

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

Если бы я должен был распечатать массив bools на консоль

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

, это дало бы следующий вывод:

10010010

достаточно просто и прямо.


Я хотел бы создать функцию constexpr, шаблон функции, лямбду или их комбинацию, которая может выполняться во время компиляции или во время выполнения в зависимости от контекста, в котором он используется для того, чтобы я мог взять каждое из этих логических значений 0 и 1 и сохранить их в переменной value выше. Если значение известно во время компиляции, я бы хотел, чтобы это назначение было разрешено. Если значение не известно во время компиляции, то значение будет инициализироваться 0, пока не будет обновлено, тогда оно будет использоваться в контексте времени выполнения.

Однако есть одно предупреждение, которое сначала неочевидно, но при индексации через массив индекс 0 th массива будет битом LSB value и индекс 7 th будет MSB. Таким образом, порядок битов, которые вы видите напечатанными на экране, будет иметь шестнадцатеричное значение 0x92, но значение для сохранения должно быть 01001001, которое будет иметь шестнадцатеричное значение 0x49 или 73 в десятичном, а не 146.

Выше перечислены члены в классе, где один представляет представление значения данных, а массив bools представляет битовое представление. У меня есть несколько конструкторов, в которых один будет устанавливать данные или член-значение напрямую, а другие конструкторы будут устанавливать массив bools, но мне нужно, чтобы оба этих значения оставались параллельными друг другу в течение всей жизни объекта класса, если он обновится другой должен быть изменен. Кроме того, массив bools является членом безымянного объединения с безымянной структурой из 8 отдельных bools в виде одного бита в битовом поле. У класса также есть оператор индекса для доступа к отдельным битам в виде единичных логических значений 0 или 1.


Вот как выглядит мой класс:

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];
    }
};

Итак, как я могу сделать каждое из значений в bits[] отдельными битами value, где bit[0] - младший бит value? Я также хотел бы сделать это в контексте, где он не будет генерировать UB! Или в STL под c ++ 17 уже существует алгоритм, который сделает это для меня? У меня еще нет компилятора C ++ 20 ... Я пытался включить std::uint8_t в union, но он не работает так, как мне бы хотелось, и я не ожидал, что он будет работать либо!

1 Ответ

0 голосов
/ 21 марта 2020

Я ненадолго отошел и вернулся к тому, над чем работал ... Я думаю, что короткий перерыв помог. Предложение пользователя Nicol Bolas также помогло, сообщив мне, что я могу сделать это с помощью функции constexpr. Теперь мне не нужно беспокоиться о templates или lambdas для этой части кода.

Вот функция, которую я придумала и которая, я считаю, назначит биты в соответствующем порядке. .

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;
}

Если есть какая-либо оптимизация, которая может быть выполнена, или какие-либо ошибки или запах кода, пожалуйста, дайте мне знать ...


Теперь, это просто вопрос извлечения отдельных битов и назначения их членам моего поля битов, а также отслеживания изменений любого из них, чтобы убедиться, что оба они обновляются одновременно.

...