我有一个必须从 N 到 0(包括)的循环。我的i
变量的类型size_t
通常是无符号的。我目前正在使用以下代码:
for (size_t i = N; i != (size_t) -1; --i) {
...
}
那是对的吗?有没有更好的方法来处理这种情况?
谢谢,
文森特。
是的,这是正确的,这是一种非常常见的方法。我不会考虑改变它。
无符号整数类型的算术保证使用模2^N
算术(其中N
是类型中值的位数),并且溢出的行为是明确定义的。通过加或减的倍数(即模运算)0
将结果转换为范围。2^N - 1
2^N
2^N
-1
转换为无符号整数类型(其中size_t
之一)转换为2^N - 1
. --
还对无符号类型使用模2^N
运算,因此具有值的无符号类型0
将递减为2^N - 1
. 您的循环终止条件是正确的。
就个人而言,我只会使用不同的循环结构,但每个循环结构都有自己的:
size_t i = N;
do {
...
} while (i --> 0);
(您可以只(i--)
用作循环条件,但永远不要放弃使用-->
“运算符”的机会)。
仅仅因为for
在每次迭代开始时有一个方便的地方进行测试并不意味着您必须使用它。要处理 N to 0 inclusive,测试应该在最后,至少如果您关心处理最大值。不要让便利吸引你把测试放在错误的地方。
for (size_t i = N;; --i) {
...
if (i == 0) break;
}
一个 do-while 循环也可以工作,但是你会另外放弃i
被限制在循环中。
你可以使用这个:
for (size_t i = n + 1; i-- > 0;)
{
}
希望有帮助。
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 <= N 但在循环中的任何地方都使用 (Ni) 而不是 i 。例如, myArray[i] 将变为 myArray[Ni] (根据 N 的值实际表示的值减一)。
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 并执行。
您可以使用第二个变量作为循环计数器,以使未来的审阅者清楚地了解迭代范围。
for (size_t j=0, i=N; j<=N; ++j, --i) {
// code here ignores j and uses i which runs from N to 0
...
}
for (i=N; i+1; i--)
由于无符号整数从零递减时会滚动到其最大值,因此您可以尝试以下操作,前提N
是小于该最大值(如果这是UB ,请有人纠正我):
for ( size_t i = N; i <= N; i-- ) { /* ... */ }