C-为什么在使用uint64_t计数器时for循环会卡住,而while循环是';T

C-为什么在使用uint64_t计数器时for循环会卡住,而while循环是';T,c,for-loop,while-loop,uint64,C,For Loop,While Loop,Uint64,当我使用带有uint64\u t的for循环作为计数器时,它会永远卡住,即使条件似乎定义得很好 冒犯性的MCVE #include <stdio.h> #include <inttypes.h> int main() { uint64_t i; for (i = 15; i >= 0; i--) { printf("%"PRIu64" ", i); } return 0; } #include <stdio.h> #inclu

当我使用带有
uint64\u t
for
循环作为计数器时,它会永远卡住,即使条件似乎定义得很好

冒犯性的MCVE

#include <stdio.h>
#include <inttypes.h>

int main() {
    uint64_t i;
    for (i = 15; i >= 0; i--) { printf("%"PRIu64" ", i); }
    return 0;
}
#include <stdio.h>
#include <inttypes.h>

int main() {
    uint64_t i = 16;
    while (i--) { printf("%"PRIu64" ", i); }
    return 0;
}
它似乎忽略了停止条件,所以它翻滚了

但是,将其更改为“等效”while循环时,一切正常:

正确的MCVE

#include <stdio.h>
#include <inttypes.h>

int main() {
    uint64_t i;
    for (i = 15; i >= 0; i--) { printf("%"PRIu64" ", i); }
    return 0;
}
#include <stdio.h>
#include <inttypes.h>

int main() {
    uint64_t i = 16;
    while (i--) { printf("%"PRIu64" ", i); }
    return 0;
}

for
循环中使用
uint64\u t
计数器时,我是否遗漏了一些内容?非常感谢您的帮助

如果
i
是无符号类型,则条件
i>=0
通常为真。递减无符号零不会产生负值,但计数器将换行到给定类型的最大可表示数

C表示包含下限和排除上限的范围。例如,
N
元素数组的索引为0到
N-1
。上限本身不是有效的数组索引

此约定意味着您在递增某个值之前使用该值,但在使用该值之前先取消该值。考虑一个简单的堆栈:

    stack[nstack++] = x;      // push a value
    x = stack[--nstack];      // pop a value
同样的逻辑也适用于循环:向前移动时,在递增之前使用该值:

    for (var i = 0; i < N; i++) { use(i); }
此循环相当于您的
while
。在处理主体之后发生的更新部分在这里是空的。在进入循环之前对值进行检查;循环体具有更新的值

对于空的更新部分,这种向后循环可能看起来很尴尬,但在其他方面,它与向前版本正交:

  • 它使用实际边界;没有必要从
    N-1开始
    
  • 它同样适用于任意边界,只要它们遵循包容下界和排斥上界的约定
  • 测试是一个纯粹的不等式,而不是一个大于/小于或等于的比较

如果
i
为无符号整数类型,则表达式
i>=0
始终为真。另一种简单的方法是将其更改为:

uint64_t i;
for (i = 15; i != -1; i--) { ... }
i != (uint64_t)-1
无论
i
是有符号整数还是无符号整数,这都有效。在
uint64\u t
情况下,-1将首先转换为
0xffffffffffff
,然后与
i
进行比较

如果要消除编译警告,请将其更改为:

uint64_t i;
for (i = 15; i != -1; i--) { ... }
i != (uint64_t)-1

但是您需要确保
uint64\t
的类型恰好是
i

i>=0
对于未签名的对象始终为真。i=0后,它将环绕到最大值,而不是-1,因此如果使用GCC,停止表达式不会为假,始终使用
-Wall-Wextra
进行编译,以获取有关此类问题的有用警告。如果使用MSVC编译,请使用
-Wall
.i>=0始终为true,您可以将其更改为i!=-等效的
,而
循环将是
uint64\t i;i=15;而(i>=0){printf(“%”PRIu64“,i);i--;}
。这也会显示一个无限循环,就像您的
for
循环一样。另请参见@logo\u writer,您可以随时更改要接受的答案。只需等待一天,选择最佳答案。其他读者稍后可能会提供更好的答案。