使用 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<unsigned char>(*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 的形式运行函数