use*_*254 3 c++ unsigned compiler-errors
我从我想要使用的库中获取此代码.在编译时,我收到以下警告:
警告C4146:一元减号运算符应用于无符号类型,结果仍未签名
inline int lastbit (uint32_t v)
{
int r;
static const int MultiplyDeBruijnBitPosition[32] =
{
0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
};
r = MultiplyDeBruijnBitPosition[((uint32_t)((v & -v) * 0x077CB531U)) >> 27];
return r;
}
Run Code Online (Sandbox Code Playgroud)
如何通过尽可能少地更改库来修复它?
vis 的类型,是std::uint32_t无符号类型.无符号类型通常用于索引和计数,因为它们永远不会是负数.
试图在无符号数字上翻转符号通常是可疑的,这就是编译器发出警告的原因.然而,在这种情况下,它是安全且定义明确的,并且库依赖于在无符号数字上翻转符号的确切含义的细节.
从C++ 11标准:
通过从2 ^ n中减去其值来计算无符号数量的负数,其中n是提升的操作数中的位数.结果的类型是提升的操作数的类型.[第5.3.1.8节]
[标准表示2 ^ n,这意味着字面意思,即使2 ^ n不能用无符号类型的n位表示.在不使用更大类型的情况下实现此方法的最常见方法是翻转所有位,然后添加一个: neg_v = ~v + 1;.
要说服编译器此操作正常,您可以尝试使用强制转换.(当您需要强制编译器将值视为其自然类型的其他值时,应该很少使用强制转换.)
const uint32_t neg_v = static_cast<uint32_t>(-static_cast<int32_t>(v));
r = MultiplyDeBruijnBitPosition[((uint32_t)((v & neg_v) * 0x077CB531U)) >> 27];
Run Code Online (Sandbox Code Playgroud)
内部强制转换要求编译器转换v为32位有符号整数.对于v最多2 ^ 31 - 1的值,这会产生相同的值.对于较大的值v,这将导致负值.
但是现在你正在翻转一个有符号值的符号(编译器很乐意这样做),但标准不再能保证它完全相同.(所有现代机器都使用二进制补码,因此实际上它会产生相同的结果.)
如果你想要挑剔(像我一样),你可以使用上面的二进制补码技巧直接对无符号值执行按位运算.而不是-v,你有(~v + 1u):
r = MultiplyDeBruijnBitPosition[((uint32_t)((v & (~v + 1u)) * 0x077CB531U)) >> 27];
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2691 次 |
| 最近记录: |