【问题标题】:2^32 - 1 not part of uint32_t?2^32 - 1 不是 uint32_t 的一部分?
【发布时间】:2016-09-23 18:03:59
【问题描述】:

这是编译输出让我哭的程序:

#include <inttypes.h>

int main()
{
        uint32_t limit = (1 << 32) - 1; // 2^32 - 1 right?
}

这是编译输出:

~/workspace/CCode$ gcc uint32.c 
uint32.c: In function ‘main’:
uint32.c:5:29: warning: left shift count >= width of type [-Wshift-count-overflow]
         uint32_t limit = (1 << 32) - 1; // 2^32 - 1 right?

我认为(1 &lt;&lt; 32) - 1 等于 2^32 - 1 并且 32 位上的无符号整数范围从 0 到 2^32 - 1,不是吗?我哪里做错了?

【问题讨论】:

  • 对于 32 位 int,2^32 - 1 将适合(无符号)...问题是,2^32 不会,它是您计算 2^32- 表达式的一部分1 与。但是,由于其他原因,您最终可能会得到正确的答案,因为 uint32_t 将以 2^32 为模。
  • 为什么不只是0xFFFFFFFF
  • @jxh 1ULL
  • ULL 后缀表示常量属于unsigned long long
  • @Simonlbc 这是一个unsigned long long 字面量,至少有 64 位宽。

标签: c uint32


【解决方案1】:

警告是正确的,32 位数字中的最高位是第 31 位(索引为 0),因此溢出前的最大移位是1 &lt;&lt; 30(30 因为符号位)。即使您在某些时候执行-1,也必须存储1 &lt;&lt; 32 的结果并将其存储在int 中(在这种情况下恰好是32 位)。因此,您会收到警告。

如果您真的需要获得32 bit unsigned int 的最大值,您应该以简洁的方式进行:

#include <stdint.h>

uint32_t limit = UINT32_MAX;

或者更好的是,使用 c++ 限制标头:

#include <limits>
auto limit = std::numeric_limits<uint32_t>::max();

【讨论】:

  • 1 &lt;&lt; 31 也是未定义的行为(转移到符号位)
  • ... 除非int 大于 32 位。
【解决方案2】:

你有两个错误:

  • 1 的类型为 int,因此您将初始值计算为 int,而不是 uint32_t
  • 正如警告所说,移位运算符的移位参数必须小于类型的宽度。 1 &lt;&lt; 32未定义的行为,如果 int 是 32 位或更少。 (uint32_t)1 &lt;&lt; 32 也将是未定义的。

(另外,请注意 1 &lt;&lt; 31 也将是未定义的行为,如果 int 是 32 位,因为溢出)

由于算术无论如何都是以 2^32 为模完成的,因此更简单的方法就是

uint32_t x = -1;
uint32_t y = (uint32_t)0 - 1; // this way avoids compiler warnings

【讨论】:

  • 这在我看来像 C++!
  • 是 1 in -1 类型转换为 uint32_t 吗?为什么效果很好?
  • @Simonlbc:整数提升规则保证计算将以足够大的有符号整数类型执行,以表示uint32_t 的每个元素,或者如果没有这样的东西,在uint32_t本身。无论哪种方式,最终结果都是一个定义明确的数字,相当于-12^32。如果您愿意,也可以将 1 转换为 uint32_t 也没有什么坏处。
  • @Simonlbc 它使用模 2^32 算术。你也可以只做uint32_t x = -1;,这是完全合法的(假设实现了uint32_t),尽管有些编译器可能会发出警告。
  • 对;我做0-1 是为了让编译器放心;如果您愿意忍受警告或决定不启用该警告,您可以直接执行-1...但我更喜欢启用警告并进行无警告构建。
【解决方案3】:

编译器在尝试计算目标常量时在您的示例中内部使用 int。想象一下,rhe 编译器没有任何优化可用,而是为您的班次生成汇编程序。对于 32 位 int 移位指令来说,数字 32 太大了。

另外,如果您想设置所有位,请使用 ~0

【讨论】:

  • ~0u 更适合位摆弄,特别是考虑到 OP 想要无符号结果。
  • 具体来说,OP 想要一个具有最大值的 uint32_t 结果,所以如果编译器的 unsigned int 小于 32 位宽,即使 ~0u 也是错误的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-15
  • 2016-07-19
  • 1970-01-01
  • 2017-01-24
  • 1970-01-01
相关资源
最近更新 更多