Перевод шестнадцатеричной цифры в бинарный вид
Как перевести 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 шт):
Ну ладно, раз пошла такая пьянка...
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
Пример табличного доступа:
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]);
Можно еще добавить синтаксического сахара, реализовав пользовательский литерал:
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';
}
Элементарно же!
#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';
}