size_t r = 0;
r--;
const bool result = (r == -1);
严格来说,价值result
是实现定义的。实际上,几乎可以肯定的是true
;如果有一个实现,我会感到惊讶false
.
的价值r
after r--
的值是SIZE_MAX
,定义在中的宏<stddef.h>
/ <cstddef>
.
为了比较r == -1
, the 常见的算术转换对两个操作数都执行。通常算术转换的第一步是应用积分促销到两个操作数。
r
属于类型size_t
,实现定义的无符号整数类型。-1
是类型的表达式int
.
在大多数系统上,size_t
至少与int
。在此类系统上,积分促销会带来以下价值:r
要么转换为unsigned int
或保留其现有类型(前者可能发生,如果size_t
具有相同的宽度int
,但转化排名较低)。现在,左操作数(无符号)至少具有右操作数(有符号)的秩。右操作数转换为左操作数的类型。此转换产生的值与r
,因此相等比较产生true
.
这是“正常”情况。
假设我们有一个实现,其中size_t
是 16 位(假设它是typedef
for unsigned short
) and int
是32位的。所以SIZE_MAX == 65535
and INT_MAX == 2147483647
。或者我们可以有一个 32 位的size_t
和 64 位int
。我怀疑是否存在任何此类实现,但标准中没有任何内容禁止它(见下文)。
现在比较的左侧有类型size_t
和价值65535
. Since signed int
可以代表type的所有值size_t
,积分促销将价值转换为65535
of type int
。两侧==
运算符有类型int
,所以与通常的算术转换无关。该表达式相当于65535 == -1
,这显然是false
.
正如我提到的,这种事情不太可能发生在类型表达式中size_t
-- 但对于较窄的无符号类型很容易发生这种情况。例如,如果r
被声明为unsigned short
, or an unsigned char
,甚至是一个简单的char
在该类型有符号的系统上,result
可能会是false
。 (我说可能是因为short
甚至unsigned char
可以具有相同的宽度int
, 在这种情况下result
将true
.)
在实践中,您可以通过显式执行转换而不是依赖于实现定义的常见算术转换来避免潜在的问题:
const bool result = (r == (size_t)-1);
or
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 [支持类型]
size_t
18.2 第 6-7 段:
6 类型size_t
是实现定义的无符号整数类型
它足够大以包含任何对象的字节大小。
7 [ Note:建议实现选择类型ptrdiff_t
and size_t
其整数转换等级 (4.13) 为 no
大于signed long int
除非尺寸更大
必须包含所有可能的值。 ——尾注]
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.