【问题标题】:What happens when a integer overflow occurs in a C expression?当 C 表达式中发生整数溢出时会发生什么?
【发布时间】:2014-10-04 18:23:19
【问题描述】:

我有以下 C 代码:

uint8_t firstValue = 111;
uint8_t secondValue = 145;
uint16_t temp = firstValue + secondValue;
if (temp > 0xFF) {
    return true;
}
return false;

这是替代实现:

uint8_t firstValue = 111;
uint8_t secondValue = 145;
if (firstValue + secondValue > 0xFF) {
    return true;
}
return false;

第一个例子很明显,uint16_t 类型足够大,可以包含结果。 当我在 OS/X 上使用clang 编译器尝试第二个示例时,它正确返回了 true。那里会发生什么?是否有某种 临时 更大的类型来包含结果?

【问题讨论】:

  • 对于无符号类型,结果是“应该是什么”,以接收变量的大小为模。我的意思是:只存储适合的位;其余的(如果有的话)被忽略。对于有符号类型,结果是未定义的。

标签: c integer-overflow integer-promotion


【解决方案1】:

+ 的操作数被提升为更大的类型,我们可以通过转到 draft C99 standard 部分看到这一点 6.5.6 加法运算符 说:

如果两个操作数都具有算术类型,则通常的算术转换在 他们。

如果我们转到6.3.1.8 通常的算术转换,它会说:

否则,对两个操作数都执行整数提升。

然后我们转到6.3.1.1 布尔值、字符和整数,上面写着(强调我的):

如果一个int可以表示原始类型的所有值,则将该值转换为一个int; 否则,它将转换为无符号整数。 这些被称为整数 促销活动.48) 所有其他类型都不会因整数促销活动而改变。

所以这种情况下+的两个操作数都会被提升为类型int进行操作,所以不会溢出。

注意,Why must a short be converted to an int before arithmetic operations in C and C++? 解释了促销的基本原理。

【讨论】:

    【解决方案2】:

    第一个例子很明显,uint16_t 类型足够大,可以包含结果。

    事实上,赋值x = expr; 的目标左值xexpr 中是否存在溢出无关。如果有,那么无论x 有多宽,结果都是这样。

    在您的示例中,“整数提升”适用,并且计算在 int 操作数之间完成。这意味着没有溢出。整数提升在 C11 的第 6.3.1.1:2 节中进行了描述。

    如果您添加了两个 uint32_t 值,则可能存在回绕(当无符号操作产生超出无符号类型范围的结果时的指定行为),即使分配给结果的左值是uint64_t

    【讨论】:

    • +1 你和 Jens 在我之后就直接回答了,我实际上是在等着看是否有人会提供更好的答案,我原本打算只发表评论。
    【解决方案3】:

    是的,所有算术是在至少具有int 宽度的类型中完成的。因此,您的操作数首先转换为int,然后执行操作。与您的第一个示例一样,然后将结果转换回分配的目标类型。

    通常,对窄类型进行算术运算根本不是一个好主意。尽可能避免,它只会使事情复杂化。最好是完全避免使用这些类型,除非您在存储大量数字时遇到真正的问题,例如

    【讨论】:

      【解决方案4】:

      在 C 中,中间结果至少以int 的形式完成,如果输入类型为 long 或更大的数据类型,则更宽。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-06-20
        • 2017-09-04
        • 1970-01-01
        • 2014-05-08
        • 1970-01-01
        • 2013-07-07
        相关资源
        最近更新 更多