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]"。
为什么第一代码不会溢出?
-
如果输出0,则第一个示例确实溢出。那就是当无符号整数变量溢出时发生的事情:它回绕为0。您是否在问为什么没有编译器警告?答案很简单:溢出不是在编译时发生的,而是在运行时发生的。 (无论如何,运行时溢出是定义明确的,并且通常是有意的。它不是错误。编译时溢出通常是。)
-
两种代码具有相同的效果,编译器在决定何时显示警告时并不十分准确。
-
详细信息:这里没有溢出。 var1 + 1和255+ 1都不会溢出。 int溢出是UB。而是从int到unsigned char的转换。定义明确。整数溢出与转换问题有一些相似之处,但是C对它们的指定有所不同。
-
@chux AFAIK,unsigned(OP使用)溢出是在C语言中定义的。当然,同意我们这里没有溢出,但可以通过var1 = var1 + (unsigned char)1;引入。
-
当var1是8位unsigned char时,@ GermanNerd var1 + (unsigned char)1不会溢出。在加法之前,两者都经过了通常的算术转换,并成为int,至少为16位。然后,总和在范围内:无溢出。如果总和超过255,对unsigned char的赋值将导致减少,但重新开始,这不会在C中溢出。
-
@chux有趣的是,几十年来,我一直想着只有在整数类型不匹配时才进行整数提升...当前行为在C中是否一直如此?并感谢您的澄清。
-
@GermanNerd在大多数情况下,排名小于intunsigned的操作数将进行通常的算术转换(然后,当类型不匹配时,可能会发生转换)。我相信那是从C89开始的。
-
有趣。我不知道为什么要做出这个决定;对我来说似乎不一致。那unsigned char a_byte = 255; a_byte++;呢?那是溢出吗?
-
@GermanNerd"已做出决定"以简化操作类型的可能性,因为intunsigned是首选大小。
无符号字符(基本上是一个字节)的环绕是设计使然。
但是,您的第二个示例将添加两个整数。从int的256转换为字节的零会构成信息丢失;因此警告。
-
第一种情况还将int值256转换为字节(整数提升适用于var1 + 1中的操作数)
-
然后,可能由于以下事实而发出警告:编译器可以在编译时告知在第二个示例中将发生精度损失。 字节的环绕仍然是设计使然,不会在运行时引起错误。
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模。类似的方法适用于所有其他无符号整数类型的转换,以及对实际完成的无符号类型的算术运算。
-
详细信息:无溢出。 OP是经验转换问题。
-
@chux,我想多数民众赞成在一个术语问题。 我在此答案中使用"溢出"的OP(和GCC)定义,我同意,这与标准不同。
-
约翰,令人失望的是,我找不到关于现代gcc的" -Woverflow"定义的详细信息。