假设我想在for
循环中迭代所有整数。为了便于讨论,假设我为每个整数调用一些未知函数f(unsigned x)
:
for (unsigned i = 0; i < UINT_MAX; i++) {
f(i);
}
当然,上面的代码无法迭代所有整数,因为它错过了一个:UINT_MAX。将条件更改为i <= UINT_MAX
只会导致无限循环,因为这是一个重言式。
您可以使用do-while
循环执行此操作,但会丢失for
语法的所有细节。
我可以吃蛋糕(for
循环)并吃掉它(迭代所有整数)吗?
答案 0 :(得分:8)
你必须在循环体的末尾执行测试,就像做一次:
for (unsigned int i = 0; /* nothing */; i++) {
...
if (i == UINT_MAX) {
break;
}
}
要使循环测试位置标准中的测试起作用,您需要以区分UINT_MAX + 2状态的方式跟踪当前迭代:每次进入循环体时一个,一个用于有一次你没有。单个unsigned int无法处理,因此您需要至少一个辅助变量或更大的循环计数器。
答案 1 :(得分:5)
你可以通过do-while循环来完成它,但是你会失去所有的细节 用于语法。
使用匿名块作用域仍可以使用do-while循环:
{
unsigned i = 0;
do { f(i); } while (++i != 0);
}
虽然这种结构可能不是最惯用的,但它显然是清晰汇编代码的候选者。例如,gcc -O
将其编译为:
.L2:
mov edi, ebx ; ebx starts with zero
call f
add rbx, 1
cmp rbx, rbp ; rbp is set with 4294967296
jne .L2
答案 2 :(得分:3)
你可以使用另一个变量来检测你何时循环。
for (unsigned int i = 0, repeat = 0; !(i == 0 && repeat); i++, repeat = 1) {
...
}
答案 3 :(得分:2)
通过单个测试有效实现迭代的经典方法是do / while
循环:
unsigned i = 0;
do { f(i); } while (i++ != UINT_MAX);
如果您坚持使用for
循环:
for (unsigned i = 0;; i++) {
f(i);
if (i == UINT_MAX)
break;
}
这是另一个带有2个变量的变体,其中所有逻辑都在for
表达式中:
for (unsigned int i = 0, not_done = 1; not_done; not_done = (i++ - UINT_MAX)) {
f(i);
}
由于额外的变量,它可能会产生较慢的代码,但正如BeeOnRope评论的那样,clang
和icc
将其编译为very efficient code。
答案 4 :(得分:0)
一个简单的解决方案就是,
unsigned i;
for (i=0; i<UINT_MAX; i++) {
f(i);
}
f(i); // i will be UINT_MAX at this time.
答案 5 :(得分:0)
使用更大的整数类型:
#include <limits.h>
#include <stdio.h>
int main() {
for (unsigned long i = 0; i <= UINT_MAX; i++) {
f(i);
}
}
此版本使用stdint来提高一致性
#include <stdio.h>
#include <stdint.h>
int main() {
for (uint_fast64_t i = 0; i <= UINT32_MAX; ++i) {
f(i);
}
}