For循环退出条件(size_t vs. int)

For Loop Exit Condition (size_t vs. int)

本文关键字:vs int size 循环 退出 条件 For      更新时间:2023-10-16

当我在程序中输入以下内容时:

for (size_t i = VectorOfStructs.size()-1; i > 0; i--)

它可以正常工作,但"i"永远不会等于0。所以,我不能访问第一个元素(VectorOfStructs[0])。

如果我把它改成:

for (size_t i = VectorOfStructs.size()-1; i > -1; i--)

程序甚至没有进入for循环!但是,如果我把它改成如下:

for (int i = VectorOfStructs.size()-1; i > -1; i--)

它完全按照我想要的方式工作(遍历所有元素)。

所以,我的问题是:

(A)为什么第二个代码段执行失败?

(B)为什么第三个代码片段相应地执行而第二个代码片段没有执行?

任何见解将不胜感激!

所有的循环都是向前的,即使是向后的。

你想要的是:

for (std::size_t i = 0, e = VectorOfStructs.size(); i != e; ++i)
{
    std::size_t const ri = e - i - 1;
    // use "VectorOfStructs[ri]"
}

或更好:

for (auto rit = VectorOfStructs.rbegin(); rit != VectorOfStructs.rend(); ++rit)
{
    // use "*rit"
}

(第二个代码段失败了,因为i是无符号的,所以-1被转换为与i相同的类型,并成为最大的可表示值,因此比较始终为真。相比之下,i在第三个代码片段中被签名。)

第二个例子使用size_t作为i的类型,这是一个unsigned类型,因此它永远不会有负值;这也意味着它不能恰当地与-1

进行比较。

但是(int)-1是位表示为0xFFFFFFFF的,这对于size_t来说代表了一个相当大的数字(2^32-1)。i>0xFFFFFFFF不可能为真,因为0xFFFFFFFsize_t所能容纳的最大值。

第三个例子使用signed int(允许负数,因此测试成功)。

这个应该可以工作:

for (size_t i = VectorOfStructs.size(); i-- > 0;) {
  use(VectorOfStructs[i]);
}

在第二个例子中,你将变量'i'与-1进行比较,这里它的类型是size_t, size不能为负,所以它失败了。

在第三个例子中,'i'是整数类型,整数的范围从-32568到+32567(对于int=2字节的系统)

总的size_t变量不能为负值,因为物理内存将在系统中存在

为什么第二个代码段执行失败?

size_t是无符号的,所以根据定义它永远不是负的。所以循环条件总是为真。变量"wrap around"为最大值

size_t是unsigned类型,所以-1size_t可以接受的最大值。在第二个代码片段中,size_t不能大于这个最大值,因此不进入循环。

另一方面,int是有符号类型,因此与-1的比较如您所料。

Int和size_t都是整数类型,但Int既可以保存负数也可以保存正数。Int的取值范围是-2^31 -1到2^31 -1,size_t的取值范围是0到2^32 -1

现在,当你写int a = -1时它确实是-1但是当你用size_t这样做时你得到的是int的最大值2^32 -1

所以在第二段代码中size_t的值不会超过-1因为它实际上是2^32 -1

在第三个代码片段中,比较的类型是int,当将int与-1比较时,它会将其视为-1,因此它按照您计划的方式执行

当编译器看到i > -1并注意到子表达式i-1具有不同的类型时,它将它们都转换为通用类型。如果这两种类型(std::size_tint)具有相同的位数,这似乎是您的编译器的情况,则通用类型是无符号类型(std::size_t)。因此表达式等于i > (std::size_t)-1。但是当然(std::size_t)-1size_t的最大值,所以比较总是假的。

大多数编译器都有一个关于总是为真或总是为假的比较的警告,原因如下。

当你比较'signed'和'unsigned'时,'signed'值首先被转换为'unsigned'值。这包括(#1)和(#2),有一个问题'unsigned(0-1)'和'some unsigned'> 'unsigned max'。

然而,通过强制'signed'/'signed'比较(#3)使其工作,您将失去'unsigned'范围的一半。

你可以这样做:

for(size_t n = vector.size(); n; /* no -- here */ ) {
   --n;
   // vector[n];
}

注意:unsigned(-1)在很多系统上是最大的无符号整数值。