2014-01-31 6 views
12

Ниже вы найдете строковый литерал constexpr для вычисления CRC32.Альтернатива reinterpret_cast с функциями constexpr

Мне пришлось переосмыслить строковый литерал от 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++) достаточно.

ответ

9

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

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

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

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

2 - Если тип назначения без знака, полученное значение является наименее целым числом без знака конгруэнтны исходного целое (по модулю 2 n где 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; 
} 
+0

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

+0

Думая об этом, я могу просто добавить 128 символов и безопасно индексировать в 'm_'. – galop1n

+1

@ galop1n вы можете просто отличить от 'char' до' unsigned char' - см. Выше. – ecatmur

 Смежные вопросы

  • Нет связанных вопросов^_^