迭代for循环中的所有无符号整数
假设我想迭代for
循环中的所有整数。 为了便于讨论,假设我为每个整数调用一些未知函数f(unsigned x)
:
for (unsigned i = 0; i < UINT_MAX; i++) { f(i); }
当然,上面的代码无法遍历所有整数,因为它错过了一个:UINT_MAX。 将条件更改为i <= UINT_MAX
只会导致无限循环,因为这是一个重言式。
你可以使用do-while
循环来完成它,但是你会失去for
语法的所有细节。
我可以吃蛋糕( for
循环)并吃掉它(迭代所有整数)吗?
你可以使用do-while循环来完成它,但是你会失去for语法的所有细节。
通过使用匿名块作用域,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
你必须在循环体的末尾执行测试,就像一个do-while:
for (unsigned int i = 0; /* nothing */; i++) { ... if (i == UINT_MAX) { break; } }
要使循环测试位置标准中的测试起作用,您需要以能够区分UINT_MAX + 2状态的方式跟踪当前迭代:每次进入循环体时都有一个状态,一次是您的一次别。 单个unsigned int无法处理,因此您至少需要一个辅助变量或更大的循环计数器。
你可以使用另一个变量来检测你何时循环。
for (unsigned int i = 0, repeat = 0; !(i == 0 && repeat); i++, repeat = 1) { ... }
通过单个测试有效实现迭代的经典方法是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
编译为非常高效的代码 。
一个简单的解决方案是,
unsigned i; for (i=0; i
使用更大的整数类型:
#include #include int main() { for (unsigned long i = 0; i <= UINT_MAX; i++) { f(i); } }
此版本使用stdint以提高一致性
#include #include int main() { for (uint_fast64_t i = 0; i <= UINT32_MAX; ++i) { f(i); } }