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

Mar*_* A. 5 c standards c89 undefined-behavior unsigned-integer

解决了!

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

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

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

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

[2014-03-14]显然无符号短整数可能会溢出,导致未定义的行为,具体取决于目标环境.如果短无符号整数被算术提升为int,则会发生这种情况.详细信息请参阅更新的答案和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? */
Run Code Online (Sandbox Code Playgroud)

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

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

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

现在有6.3个"表达式"与我有关.我引用:

"[......]如果在评估表达式期间发生异常(即,如果结果未在数学上定义或不在其类型的可表示的范围内),则行为不明确.[...]"

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

  • 对操作数的通常算术转换,不适用于所有内容都是uint32_t.
  • 结果是两者的总和,显然不适合uint32_t.
  • 精细

没有任何说法,结果值被转换为结果类型 - 因此6.2.1.2不适用.但是价值明显溢出,其中6.3步.

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

我现在真的很困惑.:-)

关于,马克

问题更新

[2014-03-03]解决了

[2014-03-03] 感谢Acme我现在对ANSI C99有一个清晰而完整的答案(参见答案: "无符号整数减法定义的行为":明确定义的行为如预期的那样.虽然我期望这样鉴于上面的文字段落,我仍然无法从ISO 9899:1990的文本中读取ANSI C90.所以我认为我的问题暂时还没有答案.

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

Kei*_*son 6

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

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

涉及无符号操作数的计算永远不会溢出,因为无法用结果无符号整数类型表示的结果以比模式生成的无符号整数类型所表示的最大值大1的数量减少.

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

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

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

unsigned short US = USHRT_MAX; // 65536
Run Code Online (Sandbox Code Playgroud)

表达式中的两个操作数

us * us
Run Code Online (Sandbox Code Playgroud)

从被提升unsigned shortint(因为int可容纳类型的所有可能的值unsigned short) -但产品,这是近2 32,不适合在一个32位 int.

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

  • @KeithThompson:如果它的宽度恰好是它的两倍,也会发生.在具有64位整数的机器上,`uint32_t a = 3037000500u; uint32_b = a*a;`将生成未定义的行为.我不确定是否有任何好的高效便携方法来将两个uint32_t相乘以产生uint32_t结果.转换为uint64_t会起作用,但它很可怕.在`int`小于32位的嵌入式控制器上,转换为`unsigned`会失败. (2认同)