C90中无符号整数加法和未定义行为

时间:2014-02-28 13:34:17

标签: c standards undefined-behavior unsigned-integer c89

解决!

相关段落可在C90 ISO 9899:1990中找到6.1.2.5类型:

  

“[..]涉及无符号操作数的计算永远不会溢出,因为[...]”

因此9899:1990 6.3不能适用,因此不能是未定义的行为。

感谢Keith Thompson帮助我阅读。 : - )

[2014-03-14] 显然,无符号短整数可能会溢出,导致未定义的行为,具体取决于目标环境。如果短无符号整数被算术提升为int,则会发生这种情况。详细信息请参阅updated answer以及supercat的注释。感谢两者。 : - )

原始问题:

首先,抱歉我的英语不好......我尽我所能。这是我的第一个问题,我认为这是一个非常愚蠢的问题。

由于一些可悲的原因,我的公司仍然坚持使用ANSI C90(ANSI / ISO 9899:1990),所以我手中有这个标准的旧版本,但仍然缺少修正和修正。

我有一个非常简单的问题,并且在我学习的时候已经非常清楚地知道答案 - 直到我尝试在标准中阅读它。

如果我在添加上有无符号整数溢出会发生什么。请看这段代码:

uint32_t a,b,c;
b = UINT_MAX;
c = UINT_MAX;
a = b + c; /* Overflow here - undefined behavior? */

我所知道的就是,只要需要,无符号整数就会包裹起来,一切都很好,但并非总是如此。

现在我正在寻找标准中的相应部分。

当然,ISO 9899:1990 6.2.1.2描述了无符号整数的转换,无论何时转换。还有一点6.2.1.5“通常的算术转换”,它描述了类型如何变得更宽,主要是表达式的两个操作数具有相同的类型。

现在有6.3个“表达式”与我有关。我引用:

  

“[...]   如果在评估表达式期间发生异常(即,如果出现异常)   结果不是数学定义或不在可表示的范围内   对于它的类型)行为是不明确的。   [...]“

关于加法运算符的第6.3.6章说:

  • 操作数上的常规算术转换,不适用于所有内容uint32_t。
  • ,结果是两者的总和,显然不适合uint32_t。
  • FINE

没有说,结果值被转换为结果类型 - 因此6.2.1.2不适用。但是这个价值显然会溢出,其中6.3步。

据我所知 - 根据ISO 9899:1990,这是未定义的行为。我错过了什么? Corrigendae中有什么东西吗?我是否错过了标准中的一行或一行?

我现在很困惑。 : - )

关于, 标记

问题更新

[2014-03-03] 解决了

[2014年3月3日] 的 所以,多亏了Acme,我现在有一个明确而完整的答案 for ANSI C99 (见答案: "Is unsigned integer subtraction defined behavior"明确定义的行为符合预期。虽然我也期望对于ANSI C90 ,但鉴于上面的文字段落,我仍然无法从ISO 9899:1990的文本中读出它。所以我认为我的问题目前还没有答案

编辑:Just Typos | Edit2:添加C90&标准标签| Edit3:添加问题更新| Edit4:添加已解决的部分|编辑5:添加答案链接:-) | Edit6:更新短无符号整数溢出|编辑7:一些拼写错误

1 个答案:

答案 0 :(得分:6)

该区域从C90到C99,或从C99到C11没有显着变化。

C90 6.1.2.5(没有段落编号,但它是PDF第23页的第一段)说:

  

涉及无符号操作数的计算永远不会溢出,因为   结果无法由结果无符号整数表示   type是以大于最大值的数量减少的模数   可以由结果无符号整数类型表示的值。

几乎相同的措辞(短语“产生无符号整数类型”改变了 “结果类型”出现在C99和C11标准的6.2.5第9段中。

唯一重要的变化(我知道)是C99中关于签名转换的补充。在C90中,如果有符号或无符号值转换为有符号整数类型,并且结果无法在目标类型中表示,则结果是实现定义的。在C99和C11中,结果是实现定义的,或者引发实现定义的信号。 (我不知道任何利用许可来发出信号的编译器。)

正如supercat在评论中指出的那样,两个unsigned short的乘法可以溢出。假设short是16位,int是32位,并且整数表示是典型的(对于有符号类型的2的补码,没有填充位)。然后给出:

unsigned short US = USHRT_MAX; // 65536

表达式中的两个操作数

us * us

unsigned short升级到int(因为int可以包含unsigned short类型的所有可能值 - 但产品近2 32 ,不适合32位签名 int

(在20世纪80年代后期的C标准化过程中,委员会必须在“保值”和“无符号保留”整数促销之间做出选择。他们选择前者。使用无符号保留语义,{{1}操作数将被提升为unsigned short,并且不会发生此问题。)