一个'for'循环似乎实际上是无限的

时间:2016-12-22 07:53:03

标签: c++

我正在调试一些代码,我遇到过这一行:

for (std::size_t j = M; j <= M; --j)

(由我的老板写的,他正在度假。)

对我来说这看起来很奇怪。

它做什么?对我来说,它看起来像一个无限循环。

2 个答案:

答案 0 :(得分:68)

std::size_t由C ++标准保证为unsigned类型。如果从0减去unsigned类型,标准会保证这样做的结果是该类型的最大值。

该环绕值始终大于或等于M 1 ,因此循环终止。

因此j <= M应用于unsigned类型是一种方便的方式来说&#34;将循环运行为零然后停止&#34;。

存在替代方案,例如运行j一个比您想要的更大的内容,甚至使用幻灯片操作符 for (std::size_t j = M + 1; j --> 0; ){,虽然需要更多输入,但可以说更清晰。我猜一个缺点(除了它在第一次检查时产生的令人眼花缭乱的效果)是它没有很好地移植到没有无符号类型的语言,例如Java。

另请注意,您的老板选择的计划&#34;借用&#34; unsigned集合中的可能值:在这种情况下会发生M设置为std::numeric_limits<std::size_t>::max()的行为不正确。 事实上,在这种情况下,循环是无限的。 (这是你正在观察的吗?)你应该在代码中插入一个注释,甚至可能在那个特定条件下断言。

<小时/> 1 Mstd::numeric_limits<std::size_t>::max()的限制。

答案 1 :(得分:27)

你的老板可能尝试做的事情是从M倒计时到零,对每个号码执行一些操作。

不幸的是有一个边缘情况,确实会给你一个无限循环,M是你可以拥有的最大size_t值。并且,虽然它很好地定义了当你从零递减时无符号值会做什么,但我认为代码本身就是一个草率思维的例子,特别是因为那里有一个完全可行的解决方案而没有缺点。你老板的尝试。

更安全的变体(在我看来更具可读性,同时仍保持严格的范围限制),将是:

{
    std::size_t j = M;
    do {
        doSomethingWith(j);
    } while (j-- != 0);
}

举例来说,请参阅以下代码:

#include <iostream>
#include <cstdint>
#include <climits>
int main (void) {
    uint32_t quant = 0;
    unsigned short us = USHRT_MAX;
    std::cout << "Starting at " << us;
    do {
        quant++;
    } while (us-- != 0);
    std::cout << ", we would loop " << quant << " times.\n";
    return 0;
}

这与unsigned short基本相同,您可以看到它处理每个单个值:

Starting at 65535, we would loop 65536 times.

用上面的代码替换上面代码中的do..while循环将导致无限循环。试试吧,看看:

for (unsigned int us2 = us; us2 <= us; --us2) {
    quant++;
}