c++ - 是否将下溢的无符号整数与 -1 进行了明确的比较?

标签 c++ c++11 language-lawyer unsigned-integer signed-integer

考虑以下:

size_t r = 0;
r--;
const bool result = (r == -1);

结果初始化 result 的比较是否具有明确定义的行为?
它的结果 true 是否如我所料?


写这个问答是因为我特别不确定两个因素。
在我的回答中,它们都可以通过使用“关键[ly]”一词来识别。

这个例子的灵感来自于计数器无符号时循环条件的方法:
for (size_t r = m.size() - 1; r != -1; r--)

最佳答案

size_t r = 0;
r--;
const bool result = (r == -1);

严格来说,result 的值是实现定义的。在实践中,几乎可以肯定是 true ;如果有一个实现是 false,我会感到惊讶。 .

r 的值在 r-- 之后是 SIZE_MAX 的值, <stddef.h> 中定义的宏/<cstddef> .

比较r == -1通常的算术转换在两个操作数上执行。通常算术转换的第一步是将积分提升应用于两个操作数。

rsize_t 类型,实现定义的无符号整数类型。 -1int 类型的表达式.

在大多数系统上,size_t至少与 int 一样宽.在这样的系统上,积分提升会导致 r 的值。要么转换为unsigned int或保留其现有类型(如果 size_t 具有与 int 相同的宽度,但转换等级较低,则前者可能发生)。现在左操作数(无符号)至少具有右操作数(有符号)的等级。右操作数转换为左操作数的类型。此转换产生与 r 相同的值,因此相等比较产生 true .

这是“正常”情况。

假设我们有一个实现,其中 size_t是 16 位(假设它是 typedefunsigned short )和 int是 32 位。所以SIZE_MAX == 65535INT_MAX == 2147483647 .或者我们可以有一个 32 位的 size_t和一个 64 位 int .我怀疑是否存在任何此类实现,但标准中没有任何内容禁止它(见下文)。

现在比较左侧的类型为 size_t和值(value)65535 .自签名 int可以表示 size_t 类型的所有值,积分促销将值转换为 65535 类型为 int 。两侧==运算符的类型为 int ,所以通常的算术转换无关。该表达式等价于 65535 == -1 ,这显然是 false .

正如我所提到的,这种情况不太可能发生在 size_t 类型的表达式中。 - 但它很容易发生在较窄的无符号类型上。例如,如果 r被声明为 unsigned short , 或 unsigned char ,甚至是普通的 char在对该类型进行签名的系统上,result 的值可能是false . (我说可能是因为 short 甚至 unsigned char 可以具有与 int 相同的宽度,在这种情况下 result 将是 true 。)

在实践中,您可以通过显式进行转换而不是依赖实现定义的常用算术转换来避免潜在问题:

const bool result = (r == (size_t)-1);

const bool result = (r == SIZE_MAX);

C++11 标准引用:

  • 5.10 [expr.eq] 等式运算符
  • 5.9 [expr.rel] 关系运算符(指定执行通常的算术转换)
  • 5 [expr] 表达式,第 9 段:常用算术转换
  • 4.5 [conv.prom] 整体促销
  • 18.2 [support.types] size_t

18.2 第 6-7 段:

6 The type size_t is an implementation-defined unsigned integer type that is large enough to contain the size in bytes of any object.

7 [ Note: It is recommended that implementations choose types for ptrdiff_t and size_t whose integer conversion ranks (4.13) are no greater than that of signed long int unless a larger size is necessary to contain all the possible values. — end note ]

所以没有禁止制作size_tint 窄.我可以几乎合理地想象一个系统,其中 int是 64 位,但没有单个对象可以大于 232-1 个字节,所以 size_t是 32 位。

关于c++ - 是否将下溢的无符号整数与 -1 进行了明确的比较?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27405418/

相关文章:

c++ - fork在递归函数中的使用

C++ - 将 C++ 代码从 Visual Studio 移植到 Linux Eclipse IDE 时出现问题

c++ - boost 文件系统中 is_regular 和 is_regular_file 之间的区别

c++ - C++ shared_ptr::operator* 危险吗?

c++ - 将 std::vector 复制到 std::array

c++ - 在 multimap 中,如何获取与给定值关联的键?

c++ - 如何让 VS2015 正确地拒绝在类声明中使用类前缀?

C++ 打印时间只到一个文件!

c - 应该返回 -1 的 sprintf 编码错误是什么?

c++ - 基类的 "default"访问说明符差异的基本原理