Альтернатива reinterpret_cast с функциями constexpr

Ниже вы найдете строковый литерал constexpr для вычисления CRC32.

Мне пришлось переосмыслить символ строкового литерала из char в unsigned char, Так как reinterpret_cast недоступен в функции constexpr, обходной путь — небольшая служебная функция для дополнения Two вручную, но я немного разочарован этим.

Существует ли более элегантное решение для такого рода манипуляций?

#include <iostream>

class Crc32Gen {
uint32_t m_[256] {};

static constexpr unsigned char reinterpret_cast_schar_to_uchar( char v ) {
return v>=0 ? v : ~(v-1);
}
public:
// algorithm from http://create.stephan-brumme.com/crc32/#sarwate
constexpr Crc32Gen() {
constexpr uint32_t polynomial = 0xEDB88320;
for (unsigned int i = 0; i <= 0xFF; i++) {
uint32_t crc = i;
for (unsigned int j = 0; j < 8; j++)
crc = (crc >> 1) ^ (-int(crc & 1) & polynomial);
m_[i] = crc;
}
}

constexpr uint32_t operator()( const char* data ) const {
uint32_t crc = ~0;
while (auto c = reinterpret_cast_schar_to_uchar(*data++))
crc = (crc >> 8) ^ m_[(crc & 0xFF) ^ c];
return ~crc;
}
};
constexpr Crc32Gen const crc32Gen_;

int main() {
constexpr auto const val = crc32Gen_( "The character code for É is greater than 127" );
std::cout << std::hex << val << std::endl;
}

Изменить: в этом случае, static_cast<unsigned char>(*data++) достаточно.

12

Решение

Дополнение к двум не гарантируется стандартом; в пункте 3.9.1:

7 — […] Представления целочисленных типов
должен определять значения с использованием чистой двоичной системы счисления. [пример: этот международный стандарт
разрешает 2-х дополнения, 1-дополнения и представления знаковых величин для целочисленных типов. — конец
пример
]

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

Тем не менее, ваша функция преобразования не нужна (и, возможно, неправильно); для преобразования со знаком в без знака вы можете просто использовать стандартное интегральное преобразование (4.7):

2 — Если тип назначения не имеет знака, полученное значение будет целочисленным с наименьшим числом без знака, совпадающим с целым числом источника (по модулю 2N где N количество битов, используемых для представления типа без знака). [ Замечания: В представлении дополнения до двух это преобразование является концептуальным, и в битовой комбинации нет изменений (если нет усечения). — конечная нота ]

Исправленный код, используя static_cast::

constexpr uint32_t operator()( const char* data ) const {
uint32_t crc = ~0;
while (auto c = static_cast<unsigned char>(*data++))
crc = (crc >> 8) ^ m_[(crc & 0xFF) ^ c];
return ~crc;
}
9

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector