为什么涉及变量的操作不会在C中溢出


Why operation involving variable does not overflow in C

我在C中有这样的代码:

1
2
3
4
5
6
7
8
9
int main(){
   unsigned char var1;

   var1 = 255;
   var1 = var1 + 1;

   printf("The result is = %i", var1);

}

我认为它将溢出,因为var1的最大类型最多为255,因此当您将其递增为1时,它将为256,但结果为0。

但是,当我修改代码时,如下所示:

1
2
3
4
5
6
7
8
int main(){
   unsigned char var1;

   var1 = 255+ 1;

   printf("The result is = %i", var1);

}

结果给出了一个溢出错误,例如"警告:从'int'到'unsigned char'的无符号转换将值从'256'更改为'0'[-Woverflow]"。

为什么第一代码不会溢出?


无符号字符(基本上是一个字节)的环绕是设计使然。

但是,您的第二个示例将添加两个整数。从int的256转换为字节的零会构成信息丢失;因此警告。


Why is that the 1st code does not overflow?

第一个代码的溢出与第二个代码的溢出完全相同,并且在完全相同的位置:将总和分配给变量var1

在第一个示例中,将无符号char var1的初始值255转换为类型int,并向其添加1。然后将所得的int值256转换为类型unsigned char,根据定义,该类型涉及将其取模256 *,得到0。第二个示例完全相同,不同之处在于左操作数已经是int 255,不需要转换。计算出完全相同的总和,并执行与unsigned char完全相同的转换。一种情况与另一种情况完全一样。

区别仅在于您的特定编译器认为适合警告的内容。完全没有义务在此处发出任何警告,它自行决定选择第二个版本发出警告,但第一个版本不发出警告。

也许它认为第二个错误比第一个错误更可能构成编程错误(合理),并且警告的适当阈值介于(有争议的)之间。或者,就像@RobertHarvey在评论中建议的那样,它没有对代码进行足够深入的分析,以至于在这种情况下表达式var1 + 1肯定溢出。

*更一般而言,转换涉及将结果以模形式比结果类型的最大可表示值unsigned char多减少一倍。您有8位unsigned char,这很正常。它们的范围是0-255,因此减少量为256模。类似的方法适用于所有其他无符号整数类型的转换,以及对实际完成的无符号类型的算术运算。