Перевод шестнадцатеричной цифры в бинарный вид

Как перевести 16-ричную цифру, заданную символом, в бинарное представление c 4 битами, заданное строкой, причём так, чтобы работало и на этапе компиляции?

Пример:

constexpr auto x = convert('F'); // x = "1111"
char y = '1';
const auto z = convert(y);       // z = "0001"

Понятно, что можно сделать просто switch с 16 вариантами. Но есть ли варианты получше?

Можно считать, что символ всегда в одном регистре (не может быть одновременно F и f). Можно использовать дополнительную constexpr память, т.е. все строки выделить заранее в массив, например.


Ответы (4 шт):

Автор решения: Harry

Ну ладно, раз пошла такая пьянка...

constexpr const char * convert(char hx) {
    constexpr const char * hex[16] = {
        "0000","0001","0010","0011","0100","0101","0110","0111",
        "1000","1001","1010","1011", "1100","1101","1110","1111" };
    if (hx >= '0' && hx <= '9') return hex[hx-'0'];
    else if (hx >= 'A' && hx <= 'F') return hex[hx-'A'+10];
    else if (hx >= 'a' && hx <= 'f') return hex[hx-'a'+10];
    return nullptr;
}

Вот полный текст программы - https://ideone.com/lKWNQx

Раз никто не говорил, что делать для не-hex'ов - просто возвращаем нулевой указатель... Но если можно UB для некорректных символов - то все реализуется одной командой return:

constexpr const char * convert(char hx) {
    return "0000\0000001\0000010\0000011\0000100\0000101\0000110\0000111"
        "\0001000\0001001\0001010\0001011\0001100\0001101\0001110\0001111"
    + (hx|0x20)%87%48*5;
}

И ни одного ветвления :) Полный текст программы - https://ideone.com/qLuRYr

→ Ссылка
Автор решения: user7860670

Пример табличного доступа:

constexpr char const hex_num_to_str[17][5]
{
    "0000", "0001", "0010", "0011"
,   "0100", "0101", "0110", "0111"
,   "1000", "1001", "1010", "1011"
,   "1100", "1101", "1110", "1111"
,   ""
};

constexpr unsigned char const sym_to_hex_num[256]
{
    0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10
,   0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10
,   0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10
,   0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10
,   0x10, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10
,   0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10
,   0x10, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10
,   0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10
,   0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10
,   0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10
,   0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10
,   0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10
,   0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10
,   0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10
,   0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10
,   0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10
};

constexpr auto
lookup(char const sym) noexcept
{
    return hex_num_to_str[sym_to_hex_num[static_cast< unsigned char >(sym)]];
}

constexpr auto const t1{lookup('2')};
static_assert('0' == t1[0]);
static_assert('0' == t1[1]);
static_assert('1' == t1[2]);
static_assert('0' == t1[3]);

constexpr auto const t2{lookup('B')};
static_assert('1' == t2[0]);
static_assert('0' == t2[1]);
static_assert('1' == t2[2]);
static_assert('1' == t2[3]);

constexpr auto const t3{lookup('b')};
static_assert('1' == t3[0]);
static_assert('0' == t3[1]);
static_assert('1' == t3[2]);
static_assert('1' == t3[3]);

constexpr auto const t4{lookup('K')};
static_assert('\0' == t4[0]);
static_assert('\0' == t4[1]);
static_assert('\0' == t4[2]);
static_assert('\0' == t4[3]);

https://godbolt.org/z/F6oVyH

Можно еще добавить синтаксического сахара, реализовав пользовательский литерал:

constexpr auto
operator ""_hs(char const sym) noexcept
{
    return lookup(sym);
}

constexpr auto const str{'b'_hs};
→ Ссылка
Автор решения: вася

Вариант медленнее, чем поиск в ASCII таблице, но работает для любых кодировок:

#include <array>
#include <cstddef>
#include <iostream>


constexpr std::array hex_binary_map = {
        "0000", "0001", "0010", "0011",
        "0100", "0101", "0110", "0111",
        "1000", "1001", "1010", "1011",
        "1100", "1101", "1110", "1111",
};

constexpr std::array hex_digits = {
        '0', '1', '2', '3',
        '4', '5', '6', '7',
        '8', '9', 'A', 'B',
        'C', 'D', 'E', 'F',
};


template<typename It>
constexpr auto hex_index(It beg, It end, char hex) {
    std::size_t res = 0;

    while (*beg != hex) { // beg != end assumption
        beg += 1;
        res += 1;
    }

    return res;
}

constexpr auto convert(char hex) {
    return hex_binary_map[hex_index(hex_digits.cbegin(), hex_digits.cend(), hex)];
}


int main() {
    std::cout << convert('F') << '\n'
              << convert('A') << '\n'
              << convert('5') << '\n';
}
→ Ссылка
Автор решения: best

Элементарно же!

#include <string>
#include <bitset>
#include <iostream>

int main() {
    std::cout << std::bitset<4>{std::strtoull("F", nullptr, 16)}.to_string() << '\n';
    std::cout << std::bitset<4>{std::strtoull("A", nullptr, 16)}.to_string() << '\n';
    std::cout << std::bitset<4>{std::strtoull("5", nullptr, 16)}.to_string() << '\n';
}
→ Ссылка