我目前正在调试一些代码,并且遇到了这一行:
for (std::size_t j = M; j <= M; --j)
(由正在度假的老板写的。)
在我看来真的很奇怪。
它有什么作用?在我看来,这就像一个无限循环。
我目前正在调试一些代码,并且遇到了这一行:
for (std::size_t j = M; j <= M; --j)
(由正在度假的老板写的。)
在我看来真的很奇怪。
它有什么作用?在我看来,这就像一个无限循环。
M恰好是的最大值,该size_t怎么办?您仍然认为它很聪明吗?
#define TRUE FALSE去度假
Answers:
std::size_t由C ++标准保证是一种unsigned类型。并且,如果您将unsigned类型从0减1 ,则标准将确保这样做的结果是该类型的最大值。
该环绕值始终大于或等于M1,因此循环终止。
因此j <= M,将其应用于unsigned类型时是一种方便的方式,即“将循环运行为零然后停止”。
存在一些替代方法,例如j比您想要的运行多一个,甚至使用slide运算符 for (std::size_t j = M + 1; j --> 0; ){,尽管需要更多的键入操作,但可以说更清晰一些。我猜一个缺点(除了它在第一次检查时产生的令人困惑的效果)是,它不能很好地移植到没有无符号类型的语言,例如Java。
还要注意,老板选择的方案从unsigned集合中“借”了一个可能的值:在这种情况下,M设置为std::numeric_limits<std::size_t>::max()不会具有正确的行为。实际上,在这种情况下,循环是无限的。(这就是您正在观察的内容吗?)您应该在代码中插入对此效果的注释,甚至可能在特定条件下进行声明。
M不存在为准std::numeric_limits<std::size_t>::max()。
std::numeric_limits<std::size_t>::max()那么M + 1将为零,而for (std::size_t j = M + 1; j --> 0; )循环不会循环可言。
size_t是64位,则在边缘情况下观察错误行为将花费数百年的时间。(除非优化程序可以摆脱循环。)
你的老板可能是试图做的是从倒数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;
}
与an基本上具有相同的作用unsigned short,您可以看到它处理了每个单个值:
Starting at 65535, we would loop 65536 times.
do..while用您的老板基本上所做的替换上面代码中的循环将导致无限循环。试试看,看看:
for (unsigned int us2 = us; us2 <= us; --us2) {
quant++;
}
0。为什么不for(size_t j = M; j-- != 0; )呢?
numeric_limits<size_t>::max()。
M == 0会导致元素0未被处理,因此确实存在边缘情况。使用我的后检查do..while方法可以完全消除边缘情况。如果使用进行尝试M == 1,则会看到它同时执行1和0。类似地,以max_size_t(无论发生了什么)启动它,它将成功地从该点开始,然后递减到0(包括0)。
exitif” { j =M; for(;;){ f(j); if( j == 0 )break; j -= 1; } }。如果C语言没有命名循环,则甚至可能需要break用goto嵌套的a代替。如果“结构化”的意思是“易于对块进行推理”,则它是结构化的(布局有帮助!),如果它的含义是“对通过先决条件和后置条件进行推理也可以进行形式验证”。尽管在这种情况下j--可行,但是当需要更复杂的转换时,可以证明exitif样式是合理的。
size_t是无符号的,因此在尝试弃用零并结束循环时,可以保证回绕到最大值。仍然是可怕的代码。