【问题标题】:Why operation involving variable does not overflow in C为什么涉及变量的操作在C中不会溢出
【发布时间】:2019-01-29 12:18:34
【问题描述】:

我在 C 中有一个类似这样的代码:

int main(){
   unsigned char var1;

   var1 = 255;
   var1 = var1 + 1;

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

}

我认为它会溢出,因为 var1 的最大类型高达 255,所以当你将它增加到 1 时,它将是 256,但结果是 0。

但是当我像这样修改代码时:

int main(){
   unsigned char var1;

   var1 = 255+ 1;

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

}

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

为什么第一个代码没有溢出?

【问题讨论】:

  • 如果打印 0 则第一个示例 确实 溢出。这就是无符号整数变量溢出时会发生的情况:它回绕到 0。您是在问为什么没有编译器警告吗?答案很简单:溢出不是在编译时,而是在运行时。 (无论如何,运行时溢出是明确定义的,而且通常是故意的。这不是错误。编译时溢出通常是。)
  • 两个代码的效果相同,编译器在决定何时显示警告时并不是很准确。
  • 详情:这里没有没有溢出var1 + 1255+ 1 都不会溢出。 int 溢出是 UB。而是从intunsigned char转换。这是很好的定义。整数溢出与转换问题有一些相似之处,但 C 对它们的指定不同。
  • @chux AFAIK, unsigned(OP 使用)溢出在 C 中定义良好。当然,同意我们这里没有溢出,但可以通过 var1 = var1 + (unsigned char)1; 引入。
  • @GermanNerd var1 + (unsigned char)1var1 是 8 位 unsigned char 时不能溢出。在添加之前,两者都被认为是通常的算术转换,并成为int,它至少是 16 位的。然后总和在范围内:没有溢出。如果总和超过 255,则对 unsigned charassignment 会导致减少,但又一次,这不是 C 中的 overflow

标签: c


【解决方案1】:

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

但是,您的第二个示例是添加两个整数。从 int 中的 256 转换为 byte 中的 0 构成信息丢失;因此发出警告。

【讨论】:

  • 第一种情况还将int256转换为字节(整数提升适用于var1 + 1中的操作数)
  • 那么警告可能是由于编译器可以在编译时告诉第二个示例将发生精度损失。字节的环绕仍然是设计使然,不会在运行时导致错误。
【解决方案2】:

为什么第一个代码没有溢出?

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

在第一个示例中,unsigned char var1 的初始值 255 被转换为类型 int 并添加了 1。然后将生成的int 值 256 转换为类型 unsigned char,根据定义,这涉及对它进行模 256 减少,* 产生 0。第二个示例完全相同,除了左操作数是已经是int 255,不需要转换。计算完全相同的总和,并执行完全相同的转换为unsigned char。一种情况下的溢出量与另一种情况一样多。

区别仅在于您的特定编译器认为适合警告的内容。它根本没有义务在此处产生任何警告,它会自行决定第二个版本应该引发警告,但第一个版本不应该。

也许它认为第二个比第一个更可能构成编程错误(似是而非),并且警告的适当阈值介于两者之间(值得商榷)。或者,正如@RobertHarvey 在 cmets 中所建议的那样,它对代码的分析不够深入,无法识别出表达式 var1 + 1 在这种情况下肯定会溢出。


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

【讨论】:

  • 详细信息:no overflow。 OP 是体验转换问题。
  • @chux,我想这是一个术语问题。我在这个答案中使用了 OP(和 GCC)对“溢出”的定义,我同意,这与标准的不同。
  • 约翰,很失望,我没有找到关于现代 gcc 定义“-Woverflow”的好信息。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多