#include <stdio.h>
int main(void){
char c = 0;
int count=0;
for (;++c;)
count++;
printf("%d", count);
return 0;
}
为什么该程序打印255而不是无穷大?
答案 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个步骤。0
到255
,然后以定义良好的方式回绕到0
。仍然是255步。以下经过微妙改动的for
循环将c
的增量从 condition 部分移到 post-iteration步骤部分,因此不再确定循环运行的时间:
for (;;++c)
count++;
但是,现在您的整个程序具有未定义的行为,因为它描述了永远不会终止或执行I / O的线程。
答案 1 :(得分:1)
因为您的char
类型只能容纳0-255(或-128-127,在这种情况下无关紧要)。 255之后,它将溢出并返回到0
。 0
的值为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
。c += 1
定义为与c += 1
相同,除了c = c + 1
的左值仅计算一次。c
的操作数执行的。+
算术。由于int
表示的值至少为32,767,因此在此加法中不会出现超出范围的问题。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。