使用 constexpr 函数替代 reinterpret_cast

Posted

技术标签:

【中文标题】使用 constexpr 函数替代 reinterpret_cast【英文标题】:Alternative to reinterpret_cast with constexpr functions 【发布时间】:2014-02-24 08:29:44 【问题描述】:

下面,你会发现一个用于 CRC32 计算的 constexpr 字符串文字。

我不得不将字符串文字字符从char 重新解释为unsigned char。因为 reinterpret_cast 在 constexpr 函数中不可用,所以解决方法是手动补码的一个小实用函数,但我对它有点失望。

是否存在更优雅的解决方案来处理这种操作?

#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&lt;unsigned char&gt;(*data++) 就足够了。

【问题讨论】:

【参考方案1】:

标准不保证二进制补码;在第 3.9.1 条中:

7 - [...] 整数类型的表示 应使用纯二进制计数系统定义值。 [示例:本国际标准 允许整数类型的 2 的补码、1 的补码和有符号幅度表示。 — 结束 示例 ]

因此,任何假定二进制补码的代码都必须手动执行适当的操作。

也就是说,您的转换函数是不必要的(并且可能不正确);对于有符号到无符号的转换,您可以使用标准的整数转换 (4.7):

2 - 如果目标类型是无符号的,则结果值是与源整数一致的最小无符号整数(模 2n 其中 n em> 是用于表示无符号类型的位数)。 [ 注意: 在二进制补码表示中,这种转换是概念性的,位模式没有变化(如果没有截断)。 — 尾注 ]

更正代码,使用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; 
 

【讨论】:

寻找替代解决方案的附加参数。即使我不太可能不使用 2 的补码表示来处理 CPU。 @galop1n 你可以从char 转换为unsigned char - 见上文。 @galop1n 添加 128 假定 char 是有符号的 8 位二进制补码类型,标准不保证所有属性。 @galop1n 但CHAR_BIT 可以大于8;它只需要至少 8(C,5.2.4.2.1,引用自 3.9.1p3)。 @galop1n:另外,char 是否已签名也无法确定。在 gcc 上实际上有一个标志来控制这个属性。如果您要添加 128 并且它一开始是无符号的,那么您只会溢出足够大的值(并换行)。

以上是关于使用 constexpr 函数替代 reinterpret_cast的主要内容,如果未能解决你的问题,请参考以下文章

为啥 NVCC 对 constexpr 比非 constexpr 主机函数更严格?

为啥这个 constexpr 静态成员函数在调用时不被视为 constexpr?

为啥**不**将函数声明为`constexpr`?

以 constexpr 和不带 constexpr 的形式运行函数

constexpr 函数内的 std::experimental::optional

在非 constexpr 函数上添加的 constexpr 限定符不会触发任何警告