整数溢出如何在C中起作用?

时间:2014-09-12 18:27:53

标签: c overflow arithmetic-expressions integer-promotion

我对如何在固定点环境中处理算术计算感到困惑。 请考虑以下代码行:

/* unsigned short is 16 bit.*/
unsigned short x = 1000;
unsigned short res;

/* Case1: The following yields correct result  in res */
res = (x*544/100);

/* Case2: The following yields wrong result in res*/
res = (x*544); /* expected overflow here */
res = res/100;

所以,我的问题是: 我可以看出为什么案例2会产生错误的结果。但   - 编译器在情况1中做了什么产生了正确的结果?   - 在案例1中,算术运算不是基本相同吗?除此之外,它分为两个陈述?   - 我可以期待来自不同编译器的不同行为吗?

2 个答案:

答案 0 :(得分:5)

这是由于通常的算术转换应用于乘法的操作数然后应用于除法,这导致 short 被提升为更大的整数类型以进行计算,然后在转让时转换为

6.5.5 乘法运算符部分中的draft C99 standard说:

  

通常的算术转换是在操作数上执行的。

我们还需要注意整数常量544100将具有 int 类型,我们可以找到有关原因的详细信息问题what are default integer values?

然后,我们可以转到6.3.1.8 常规算术转换部分,最后我们会看到以下段落:

  

否则,将对两个操作数执行整数提升。那么   以下规则适用于提升的操作数:

我们最终遵循以下规则:

  

否则,如果带有符号整数类型的操作数的类型可以   表示带有unsigned的操作数类型的所有值   整数类型,然后转换具有无符号整数类型的操作数   到带有符号整数类型的操作数的类型。

所以计算结果是 int

使用-Wcoversion标记gcc,但令人惊讶的是clang不会产生警告:

warning: conversion to 'short unsigned int' from 'int' may alter its value [-Wconversion]
res = (x*544/100);
      ^

这导致你在第一种情况下称为正确的结果,因为所有计算都是在 int 中完成的,在第二种情况下你会丢失中间结果乘以你将它分配回res并将值转换为适合 short 的值。

答案 1 :(得分:-3)

程序首先计算分配的右侧部分,然后指定计算出的值。

第一个示例中,它会在分配之前计算值,以便res可以实际存储它。

第二个示例中,res = (x*544);无法容纳如此大的值并且溢出。

总之,如果你传递了short的边界,在分配编译器之前不关心