【问题标题】:For loop condition to stop at 0 when using unsigned integers?使用无符号整数时,循环条件在 0 处停止?
【发布时间】:2011-03-29 21:47:05
【问题描述】:

我有一个必须从 N 到 0(包括)的循环。我的i 变量是size_t 类型,通常是无符号的。我目前正在使用以下代码:

for (size_t i = N; i != (size_t) -1; --i) {
    ...
}

正确吗?有没有更好的方法来处理这种情况?

谢谢,

文森特。

【问题讨论】:

  • 嗯,这是一个非常好的问题。
  • size_t 保证是未签名的,并且您对(size_t)-1 的使用是正确的。只有当 N 等于该值时,您才会遇到问题...
  • @supercat:因为这发生在另一个 for 循环中,我更喜欢有另一个 for 循环来实现“同步性”。

标签: c for-loop unsigned


【解决方案1】:

你可以用这个:

for (size_t i = n + 1; i-- > 0;)
{
}

希望对您有所帮助。

【讨论】:

  • 这将从n-1 变为0,而不是从n 变为0。
  • 你说得对,我错过了“包容性”要求,这已修复,谢谢
  • 它在nSIZE_MAX 的病理情况下不起作用。当然,你可能不希望从 SIZE_MAX 迭代到 0...
【解决方案2】:

由于无符号整数在从零递减时会滚动到最大值,您可以尝试以下操作,前提是 N 小于该最大值(如果这是 UB,请有人纠正我):

for ( size_t i = N; i <= N; i-- ) { /* ... */ }

【讨论】:

  • 这可能会在每次迭代时重新加载 N 的值,这会毫无意义地损害性能。
  • 你从哪里得到这个疯狂的想法?这和for ( i = 0; i &lt; N; i++ ) 有什么不同?
【解决方案3】:
for ( size_t i = N ; i <= N ; i-- ) { .... }

这样做是因为 size_t 是一个无符号整数。无符号整数是 32 位的。当变量 i 的值为 0 时,您希望循环执行条件。如果你执行 i--,计算机会这样做

 00000000000000000000000000000000
-00000000000000000000000000000001

这会导致明显的溢出,给出值 111111111...1。对于有符号二进制补码整数,这个值显然是负数。但是,i 的类型是无符号整数,因此计算机会将 111111...1 解释为一个非常大的正值。

所以你有几个选择:

1) 执行上述操作,在发生溢出时终止循环。

2) 使循环从 i = 0 运行到 i

3) 使 for 循环的条件利用一元 -- 运算符的优先级。正如另一位用户发布的那样,

for ( size_t i = N + 1 ; i-- > 0 ; ) { ... }

这会将 i 设置为 N+1,检查条件 N+1 > 0 是否仍然成立。确实可以,但是 i-- 有副作用,所以 i 的值会递减到 i = N。继续下去,直到达到 i = 1。条件将被测试,1 > 0 为真,副作用发生, 然后 i = 0 并执行。

【讨论】:

  • 不要使用i&lt;=N 作为条件。它可能会浪费时间在每次迭代时从内存中重新加载N,如果N 恰好是SIZE_MAX,那么你就有一个无限循环。
【解决方案4】:

您可以使用第二个变量作为循环计数器,以便让未来的审阅者清楚地了解迭代范围。

for (size_t j=0, i=N; j<=N; ++j, --i) {
    // code here ignores j and uses i which runs from N to 0
    ...
}

【讨论】:

    【解决方案5】:

    是的,这是正确的,这是一种非常常见的方法。我不会考虑改变它。

    无符号整数类型的算术保证使用模2^N 算术(其中N 是类型中值的位数)并且溢出时的行为是明确定义的。通过添加或减去 2^N 的倍数(即模 2^N 算术),将结果转换为范围 02^N - 1

    -1 转换为无符号整数类型(其中size_t 为一)转换为2^N - 1-- 还对无符号类型使用模 2^N 算术,因此值为 0 的无符号类型将递减为 2^N - 1。您的循环终止条件是正确的。

    【讨论】:

      【解决方案6】:

      就我个人而言,我只会使用不同的循环结构,但每个循环结构都有自己的:

      size_t i = N;
      do {
          ...
      } while (i --> 0);
      

      (您可以只使用(i--) 作为循环条件,但千万不要错过使用--&gt;“运算符”的机会)。

      【讨论】:

      • +1 用于使用 --&gt; 运算符。 C 代码旨在被混淆,这很有趣:)
      【解决方案7】:

      for 有一个方便的地方可以在每次迭代开始时进行测试,但这并不意味着您必须使用它。要处理 N 到 0 ,测试应该在最后,至少如果您关心处理最大值的话。不要因为方便而把测试放在错误的地方。

      for (size_t i = N;; --i) {
          ...
          if (i == 0) break;
      }
      

      do-while 循环也可以工作,但你会另外放弃 i 被限定在循环范围内。

      【讨论】:

        【解决方案8】:
        for (i=N; i+1; i--)
        

        【讨论】:

        • 请注意,与除 do/while 循环和等效的 for/break 构造之外的任何解决方案一样,如果 NSIZE_MAX,这将失败。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-04-01
        • 1970-01-01
        • 1970-01-01
        • 2020-03-19
        • 2014-05-06
        相关资源
        最近更新 更多