比较下溢的无符号整数到-1明确定义? [英] Is comparing an underflowed, unsigned integer to -1 well-defined?

查看:174
本文介绍了比较下溢的无符号整数到-1明确定义?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请考虑以下

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

结果初始化 result 明确定义的行为?

和它的结果 true ,如我所料?



< hr>

这个Q& A是写的,因为我特别不确定两个因素。

他们都可以使用术语



此示例的灵感来自于循环条件当计数器无符号时:

for(size_t r = m.size() - 1; r!= -1; r - ) / sup>

解决方案

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

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



r - 之后的 SIZE_MAX 的值, code>< stddef.h> / < cstddef>



对于比较 r == -1 ,对两个操作数执行通常的算术转换。通常的算术转换的第一步是将整数促销信息应用于两个操作数。



r size_t 类型,一个实现定义的无符号整数类型。 -1 是类型 int 的表达式。



在大多数系统上, size_t 至少与 int 一样宽。在这样的系统上,整数提升使得 r 的值被转换为 unsigned int 类型(如果 size_t int 具有相同的宽度,但转换排名较低,则可能发生前者)。现在左操作数(无符号)至少具有右操作数的排名(其被签名)。右操作数转换为左操作数的类型。此转换产生与 r 相同的值,因此等式比较产生 true

$ b $假设我们有一个实现,其中 size_t b

这是正常是16位(假设它是 typedef for unsigned short )和 int 是32位。因此 SIZE_MAX == 65535 INT_MAX == 2147483647 。或者我们可以有一个32位的 size_t 和一个64位的 int



现在比较的左侧有类型 size_t 和值 65535 。由于签名 int 可以表示 size_t 类型的所有值,积分促销转换值为 int 类型的 65535 == 运算符的两侧都有类型 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]积分促销

  • support.types] size_t



18.2第6-7节:


6类型 size_t 是一个实现定义的无符号整型类型

注意:
建议实现为
选择类型 ptrdiff_t size_t 的整数转换排名(4.13)没有
大于 signed long int ,除非更大的大小是
需要包含所有可能的值。 - end note]


所以没有禁止让 size_t code> int 。我可以几乎似乎想象一个系统,其中 int 是64位,但没有单个对象可以大于2 32 -1字节,因此 size_t 为32位。


Consider the following:

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

Does the comparison whose result initialises result have well-defined behaviour?
And is its result true, as I'd expect?


This Q&A was written because I was unsure of two factors in particular.
They may both be identified by use of the term "crucial[ly]" in my answer.

This example is inspired by an approach for loop conditions when the counter is unsigned:
for (size_t r = m.size() - 1; r != -1; r--)

解决方案

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

Strictly speaking, the value of result is implementation-defined. In practice, it's almost certain to be true; I'd be surprised if there were an implementation where it's false.

The value of r after r-- is the value of SIZE_MAX, a macro defined in <stddef.h> / <cstddef>.

For the comparison r == -1, the usual arithmetic conversions are performed on both operands. The first step in the usual arithmetic conversions is to apply the integral promotions to both operands.

r is of type size_t, an implementation-defined unsigned integer type. -1 is an expression of type int.

On most systems, size_t is at least as wide as int. On such systems, the integral promotions cause the value of r either to be converted to unsigned int or to keep its existing type (the former can happen if size_t has the same width as int, but a lower conversion rank). Now the left operand (which is unsigned) has at least the rank of the right operand (which is signed). The right operand is converted to the type of the left operand. This conversion yields the same value as r, and so the equality comparison yields true.

That's the "normal" case.

Suppose we have an implementation where size_t is 16 bits (let's say it's a typedef for unsigned short) and int is 32 bits. So SIZE_MAX == 65535 and INT_MAX == 2147483647. Or we could have a 32-bit size_t and a 64-bit int. I doubt that any such implementation exists, but nothing in the standard forbids it (see below).

Now the left side of the comparison has type size_t and value 65535. Since signed int can represent all the values of type size_t, the integral promotions convert the value to 65535 of type int. Both side of the == operator have type int, so the usual arithmetic conversions have nothing to do. The expression is equivalent to 65535 == -1, which is clearly false.

As I mentioned, this kind of thing is unlikely to happen with an expression of type size_t -- but it can easily happen with narrower unsigned types. For example, if r is declared as an unsigned short, or an unsigned char, or even a plain char on a system where that type is signed, the value of result will probably be false. (I say probably because short or even unsigned char can have the same width as int, in which case result will be true.)

In practice, you can avoid the potential problem by doing the conversion explicitly rather than relying on the implementation-defined usual arithmetic conversions:

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

or

const bool result = (r == SIZE_MAX);

C++11 standard references:

  • 5.10 [expr.eq] Equality operators
  • 5.9 [expr.rel] Relational operators (specifies that the usual arithmetic conversions are performed)
  • 5 [expr] Expressions, paragraph 9: Usual arithmetic conversions
  • 4.5 [conv.prom] Integral promotions
  • 18.2 [support.types] size_t

18.2 paragraphs 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 ]

So there's no prohibition on making size_t narrower than int. I can almost plausibly imagine a system where int is 64 bits, but no single object can be bigger than 232-1 bytes so size_t is 32 bits.

这篇关于比较下溢的无符号整数到-1明确定义?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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