C语言中无符号整数在循环中的异常行为问题咨询
为什么两个看似相同的C语言循环执行次数不同?
核心原因是无符号整数与有符号整数的隐式转换规则,以及循环条件中表达式的计算时机差异:
1. 第一个循环不执行的原因
看这段代码:
unsigned int i = 0; for (int j = i - 1; j < i + 1; j++) { printf("RUN1?\n"); }
i是无符号整数,值为0,i - 1作为无符号运算会触发溢出绕回,结果是UINT_MAX(无符号整数的最大值,比如32位系统下是4294967295)。- 把
UINT_MAX赋值给int类型的j,在主流补码系统中,j会被解析为-1(这是实现定义行为,绝大多数系统均遵循此规则)。 - 循环条件
j < i + 1中,j是int,i + 1是unsigned int(因为i是无符号)。根据C语言的整数提升规则,有符号整数会被转换为无符号整数参与比较。-1转换为无符号整数后变回UINT_MAX,而i + 1的值是1,显然UINT_MAX < 1不成立,循环直接跳过。
2. 第二个循环正常执行2次的原因
代码:
int j = i - 1; int k = i + 1; for (; j < k; j++) { printf("RUN2?\n"); }
i - 1同样得到无符号的UINT_MAX,赋值给int类型的j后,j的值是-1。i + 1是无符号的1,赋值给int类型的k时,因为1在int的取值范围内,所以k的值就是1。- 循环条件
j < k是两个有符号整数之间的比较,-1 < 1成立,因此循环会执行:j从-1递增到0(第一次执行),再递增到1时不满足条件退出,总共执行2次。
3. 修正写法生效的原因
for (;j < (int)(i+1); j++) {}
这里通过强制类型转换(int)(i+1),把无符号的i+1转换成int类型,循环条件变成int之间的比较,-1 < 1成立,因此循环能正常执行。
关键知识点补充
C语言中,当不同符号的整数进行运算或比较时,会触发通常算术转换:有符号整数会被转换为无符号整数的类型。无符号整数的溢出是定义良好的(模2^N绕回),而有符号整数溢出属于未定义行为,但此场景是赋值转换,属于实现定义行为(主流系统均遵循补码规则)。
内容的提问来源于stack exchange,提问作者William Li
相关产品推荐
相关产品推荐

