在无符号类型上警告C4146负号运算符 [英] warning C4146 minus operator on unsigned type

查看:125
本文介绍了在无符号类型上警告C4146负号运算符的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有我要使用的库中的代码。编译时,出现以下警告:

I have this code from a library I want to use. On compiling, I get the following warning:

警告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;
}

如何通过尽可能少地更改库来解决它?

How can I fix it with altering the library as little as possible?

推荐答案

v 的类型为 std :: uint32_t ,这是无符号类型。无符号类型通常用于索引和计数,因为它们永远不会为负。

The type for v is std::uint32_t, which is an unsigned type. An unsigned type is typically used for indexes and counts, since they can never be negative.

尝试将符号翻转到无符号数字上通常是可疑的,这就是为什么编译器发出警告。但是,在这种情况下,它是安全且定义明确的,并且库依赖于将符号翻转到无符号数字的确切含义的详细信息。

Attempting to flip the sign on an unsigned number is generally suspicious, which is why the compiler gives a warning. In this case, however, it's safe and well-defined, and the library is relying on details of what exactly it means to flip the sign on an unsigned number.

来自C ++ 11标准:

From the C++11 standard:


无符号数量的负数通过从2 ^ n中减去其值来计算,其中n为提升操作数中的位数。结果的类型是提升的操作数的类型。 [第5.3.1.8节]

The negative of an unsigned quantity is computed by subtracting its value from the 2^n, where n is the number of bits in the promoted operand. The type of the result is the type of the promoted operand. [Section 5.3.1.8]

[标准中说2 ^ n的意思是,即使2 ^ n可以, t以n位的无符号类型表示。在不使用较大类型的情况下实现 的最常见方法是翻转所有位,然后添加一个: neg_v =〜v + 1; 。]

[Where the standard says 2^n, it means that literally, even though 2^n can't be represented in an unsigned type of n bits. The most common way to implement this without using a larger type is to flip all the bits and then add one: neg_v = ~v + 1;.]

为使编译器确信此操作是可以的,在这里,您可以尝试使用强制类型转换。 (仅在需要强制编译器将值视为其自然类型以外的其他值时,才应很少使用cast。)

To convince the compiler that this operation is OK, here, you might try to use a cast. (Casts should be used only rarely, when you need to force the compiler to treat a value as something other that its natural type.)

const uint32_t neg_v = static_cast<uint32_t>(-static_cast<int32_t>(v));
r = MultiplyDeBruijnBitPosition[((uint32_t)((v & neg_v) * 0x077CB531U)) >> 27];

内部强制转换要求编译器转换 v 为32位有符号整数。对于 v 的值,最大为2 ^ 31-1,这将导致相同的值。对于较大的 v 值,这将导致负值。

The inner cast asks the compiler to convert v to a 32-bit signed integer. For values of v up to 2^31 - 1, this results in the same value. For larger values of v, this will result in a negative value.

但是现在您要翻转符号在一个有符号的值上(编译器会很高兴地做到这一点),但是标准不再保证它做完全相同的事情。 (所有现代机器都使用二进制补码,因此实际上会得到相同的结果。)

But now you're flipping the sign on a signed value (which the compiler will happily do), but it's no longer guaranteed by the standard to do exactly the same thing. (All modern machines use two's-complement, so in effect, it will give the same result.)

如果您想挑剔,就像我一样,可以使用上面的二进制补码技巧直接对无符号值执行按位运算。而不是 -v ,您将拥有(〜v + 1u)

If you wanted to be nit-picky (like me), you could perform the bitwise operations directly on the unsigned value, using the two's-complement trick from above. Instead of -v, you'd have (~v + 1u):

r = MultiplyDeBruijnBitPosition[((uint32_t)((v & (~v + 1u)) * 0x077CB531U)) >> 27];

这篇关于在无符号类型上警告C4146负号运算符的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆