【问题标题】:Unsigned integers in C++ for loopsC++ for 循环中的无符号整数
【发布时间】:2012-02-21 01:51:49
【问题描述】:

我对 Stackoverflow 进行了一些关于 C++ 中使用无符号整数而不是有符号整数的反向循环的研究。但我仍然不明白为什么会出现问题(请参阅Unsigned int reverse iteration with for loops)。为什么下面的代码会产生分段错误?

#include <vector>
#include <iostream>
using namespace std;

int main(void)
{
    vector<double> x(10);

    for (unsigned int i = 9; i >= 0; i--)
    {
        cout << "i= " << i << endl;
        x[i] = 1.0;
    }

    cout << "x0= " << x[0] << endl;

    return 0;
}

我知道问题在于索引 i 何时将等于 0,因为存在类似溢出的情况。但我认为允许无符号整数取零值,不是吗?现在如果我用有符号整数替换它,绝对没有问题。

有人可以用无符号整数向我解释那个反向循环背后的机制吗?

非常感谢!

【问题讨论】:

  • i &gt;= 0 对于未签名的i 始终为真,因此循环永远不会终止。
  • 阅读编译器警告,它们很有用。在这种情况下,您的编译器可能应该警告您循环中的条件始终为真这一事实。
  • @dragonroot:不幸的是没有。我使用 g++ 的 -Wall 标志。您知道可以检测到此类问题的编译器标志吗?谢谢。
  • @dragonroot:我已经启用了这些警告,但编译器没有告诉我任何信息。

标签: c++ for-loop unsigned-integer


【解决方案1】:

这里的问题是无符号整数永远不会是负数。

因此,循环测试:

i >= 0

永远是真的。这样你就得到了一个无限循环。

当它低于零时,它会回绕到最大值unsigned 值。
因此,您还将越界访问x[i]

这对于有符号整数来说不是问题,因为它只会变成负数,因此会失败i &gt;= 0

因此,如果您想使用无符号整数,您可以尝试以下一种可能性:

for (unsigned int i = 9; i-- != 0; )

for (unsigned int i = 9; i != -1; i--)

这两个是由 cmets 的 GManNickG 和 AndreyT 建议的。


这是我原来的 3 个版本:

for (unsigned int i = 9; i != (unsigned)0 - 1; i--)

for (unsigned int i = 9; i != ~(unsigned)0; i--)

for (unsigned int i = 9; i != UINT_MAX; i--)

【讨论】:

  • @josefx 只有有符号整数上溢/下溢是未定义的行为。
  • for (unsigned int i = 9; i-- != 0; )
  • @GManNickG 哈。我从未考虑过将减量倾倒到测试中。 :)
  • 我不确定所有这些复杂条件的目的是什么。你可以简单地做for (unsigned int i = 9; i != -1; i--)。不需要任何演员表。与-1 的直接比较将自动执行所有必要的转换。 -1 在这种情况下等同于UINT_MAX,但-1 更好,因为它与类型无关。
  • @GManNickG 的答案很简洁,但它需要从 10 开始,而不是 9 for (unsigned int i = 10; i-- != 0; )
【解决方案2】:

问题是,您的循环允许 i 低至零,并且只希望在 i 小于 0 时退出循环。由于 i 是无符号的,它永远不会小于 0。它会翻转到 2^ 32-1。这大于向量的大小,因此会导致段错误。

【讨论】:

    【解决方案3】:

    无论unsigned int i 的值是多少,i &gt;= 0 总是正确的,所以你的for 循环永远不会结束。

    换句话说,如果在某个时刻i 为 0,而您将其递减,它仍然保持非负数,因为它包含一个巨大的数字,可能是 4294967295(即 232 -1)。

    【讨论】:

      【解决方案4】:

      问题出在这里:

      for (unsigned int i = 9; i >= 0; i--) 
      

      对于 unsigned int,您从值 9 开始,并且您的退出定义是 i >= 0,这将始终是正确的。 (unsigned int 永远不会是负数!!!)。因此,您的循环将重新开始(无限循环,因为 i=0 然后 -1 变为最大 uint)。

      【讨论】:

        【解决方案5】:

        正如你所说,在循环的最后一步之后发生的无符号数减少到零以下,会产生溢出,数字会回绕到最大值,因此我们最终会出现无限循环。

        有人可以用无符号整数向我解释那个反向循环背后的机制吗?

        对于带索引的反向循环,我首选的方法是:

        for (unsigned int i = 9; i > 0; --i) {
            cout << "i= " << x[i - 1] << endl;
        }
        

        这就是为什么因为它最接近地映射到正常循环等效项:

        for (unsigned int i = 0; i < 9; ++i) {
            cout << "i= " << x[i] << endl;
        }
        

        如果你需要多次访问索引元素并且你不想连续写 [i - 1],你可以在循环的第一行添加这样的内容:

        auto& my_element = my_vector[i - 1];
        

        【讨论】:

          猜你喜欢
          • 2017-03-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-06-29
          • 2020-03-19
          • 2021-10-04
          • 2014-04-20
          相关资源
          最近更新 更多