【问题标题】:For Loop Exit Condition (size_t vs. int) [duplicate]For循环退出条件(size_t vs. int)[重复]
【发布时间】:2015-10-18 00:13:05
【问题描述】:

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

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)为什么第二段代码sn-p执行失败?

(B) 为什么第三个代码 sn-p 会相应地执行,而第二个没有?

任何见解将不胜感激!

【问题讨论】:

  • size_t 是无符号类型,它永远不会大于(size_t)-1。大多数编译器都会为此类代码生成警告,您需要将其打开。
  • 或许更好:for (auto iter = VectorOfStructs.rbegin(); iter != VectorOfStructs.rend(); ++iter) { /* use *iter */ }
  • 如果你想向后迭代,你应该在for循环的第二部分检查i-- > 0并删除for循环的第三部分

标签: c++ for-loop int size-t


【解决方案1】:

第二个例子使用size_t作为i的类型,这是一个无符号类型,因此它永远不能有负值;这也意味着它无法与-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]);
}

【讨论】:

  • 是的,使用“--> 运算符”(请参阅​​相关的 stackoverflow 问题)
  • @BenjaminLindley :facepalm: /me 不会再使用 canonical ...
  • @KABoissonneault 嘿,在你发表评论之前我已经解决了这个问题......
【解决方案2】:

size_t 是无符号类型,所以-1size_t 可以取的最大值。在第二个 sn-p 中,size_t 不能大于这个最大值,所以不会进入循环。

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

【讨论】:

    【解决方案3】:

    为什么第二段代码sn-p执行失败?

    size_t 是无符号的,所以根据定义它永远不会是负数。所以你的循环条件总是正确的。变量“环绕”到最大值。

    【讨论】:

      【解决方案4】:

      在第二个中,您将变量 'i' 与 -1 进行比较,这里它是 size_t 类型,并且 size 不能为负数,因此它失败了。

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

      整体size_t变量不能有负值,因为系统中会有物理内存存在

      【讨论】:

      • 虽然 int 通常有 32bit == 4byte
      • 早期机器使用 2byte 来存储 Integer 变量,但现在机器将其存储在 2byte/4byte 中,具体取决于系统架构
      • 确定;这几天只是非常罕见
      • 顺便说一句,您能否详细说明非物理内存如何允许负大小?
      • 不存在任何非物理内存,好像你认为关于虚拟内存那么它也有一些物理存在
      【解决方案5】:

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

      你想要的是这个:

      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"
      }
      

      (你的第二个 sn-p 失败,因为i 是无符号的,所以-1 被转换为与i 相同的类型并成为最大可表示值,所以比较总是正确的。相比之下,@987654326 @ 在第三个 sn-p 中签名。)

      【讨论】:

      • 你有“use()”函数的链接吗?我从来没有听说过,搜索也没有结果。
      • @Donald:这只是您的代码的占位符!
      • 我不知道如何使用“*rit”。如果我这样做: int Counter=*rit;它给了我“错误:不存在从“VectorOfStructs”到“int”的合适转换函数”
      • @Donald:迭代器让您可以访问向量元素,而不是向量下标。
      【解决方案6】:

      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

      所以在第二个 sn-p 中,size_t 值永远不会超过 -1,因为它实际上是 2^32 -1

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

      【讨论】:

        【解决方案7】:

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

        由于此类原因,大多数编译器都会对始终为真或始终为假的比较发出警告。

        【讨论】:

          【解决方案8】:

          每当您比较“有符号”和“无符号”时,“有符号”值首先会转换为“无符号”。这包括 (#1) 和 (#2),在 'unsigned(0-1)' 和 'some unsigned' > 'unsigned max' 方面存在问题。

          但是,通过强制进行“有符号”/“有符号”比较 (#3) 使其工作,您会失去 1/2 的“无符号”范围。

          你可以这样做:

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

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2018-03-11
            • 2012-03-01
            • 1970-01-01
            • 2023-03-30
            • 1970-01-01
            • 2021-06-07
            • 2021-08-22
            • 1970-01-01
            相关资源
            最近更新 更多