为什么输出255而不是无穷大?

时间:2020-11-03 12:13:49

标签: c

#include <stdio.h>

int main(void){
    char c = 0;
    int count=0;
    for (;++c;)
        count++;
    printf("%d", count);
    return 0;
}

为什么该程序打印255而不是无穷大?

4 个答案:

答案 0 :(得分:3)

首先,没有整数会达到无穷大。整数具有固定的值范围。您可能曾期望int count会达到2,147,483,647(32位)或9,223,372,036,854,775,807(64位)之类的值。

之所以没有,是因为那不是您的程序所做的。仅当count作为布尔条件进行真实求值时,程序才会递增++c。一旦c本身的值用完了,这种情况就会停止。

  • 如果您的环境中签署了char,则发生在127;然后,在达到此类类型的最大可能值之后,您会遇到复杂且由实现定义的规则,在这种情况下,显然要绕回-128,然后继续进行0。那是255个步骤。
  • 如果未签名,它会从0255,然后以定义良好的方式回绕到0。仍然是255步。

以下经过微妙改动的for循环将c的增量从 condition 部分移到 post-iteration步骤部分,因此不再确定循环运行的时间:

for (;;++c)
 count++;

但是,现在您的整个程序具有未定义的行为,因为它描述了永远不会终止或执行I / O的线程。

答案 1 :(得分:1)

因为您的char类型只能容纳0-255(或-128-127,在这种情况下无关紧要)。 255之后,它将溢出并返回到00的值为false,因此for循环中断。

答案 2 :(得分:0)

计算机中的数据存储在一定数量的内存中。在这种情况下,c(类型char)存储在一个字节上,因此它可能只有256个不同的值。如果您坚持要增加它的值,它会自动换行,并且当它到达0时,for循环会再次完成。

鉴于它以0开头,并且在检查其值之前已递增,因此for循环仅运行255次;在c的第256 增量处,其值再次变为0

答案 3 :(得分:0)

简短答案

程序打印“ 255”,因为循环在c再次变为零之前循环遍历255个值,从而触发了结束循环的条件。

中等答案

C允许char签名或未签名。如果它是无符号的,则char在C实现中为8位,并且程序将其从1递增到255。下一个增量会将其重置为零,因为无符号算术和转换被定义为自动换行,并且循环停止

如果对char进行了签名,则该值超出++c范围时char的行为是实现定义的(由于{ {1}})。您的实现很可能使用一个八位字符,其值介于-128到127之间,当该值变为128时,它将被包装为-128。因此,在++再次变为零之前,计数了255个值(从1到127的127到-128到-1的128个),并且由于其测试表达式c的值为零,因此循环停止。 / p>

在C标准下在实践中不会发生的理论可能性是,您的实现使用值为-256或-255到255的9位char,并且当该值变为256时,它将重置为零。

长答案

++c是令人惊讶的复杂操作:

  • C 2018 6.5.3.1 2定义为等同于++c
  • C 2018 6.5.16.2 3将c += 1定义为与c += 1相同,除了c = c + 1的左值仅计算一次。
  • C 6.5.6 4告诉我们通常的算术转换是对c的操作数执行的。
  • 通常的算术转换在6.3中涉及几个子句,导致使用+算术。由于int表示的值至少为32,767,因此在此加法中不会出现超出范围的问题。
  • 最后,C 6.5.16.1 2告诉我们加法的结果转换为int。超出范围的值就是在这里发生有趣的事情。

C 2018 6.3.1.3告诉我们转换为char会发生什么。循环只有三种方式可以迭代255个值,然后在char中产生零:

  • c是无符号的,并且是8位,因此它表示从0到255的值。当加法产生256时,6.3.1.3 2告诉我们转换以256为模进行换行,产生零。
  • char是无符号的,8位和2的补码,因此它表示的值是-128至+127。当加法运算产生128时,6.3.1.3 3告诉我们结果是实现定义的。您的实现产生−128。之后,增量从-128到-1再到零,然后循环停止。
  • char是无符号的,没有位,因此它表示从-256或-255到+255的值。当相加产生256时,您的实现产生零。然后循环停止。 (这在正常实践中不会发生;这只是在C标准下的理论可能性。)

我们知道char是八位还是九位,因为这是计数可能为255的唯一方法。如果是七位(C标准无论如何都不允许),就无法计数255个不同的值。如果它是十位或更多,那么在实现定义的转换可以重置char之前,该计数至少增加到511。