【问题标题】:Can an unsigned integer addition invoke undefined behavior?无符号整数加法可以调用未定义的行为吗?
【发布时间】:2016-05-27 15:53:08
【问题描述】:

编辑:更改了 USHRT_MAX 的值,因为它与 cmets 显示的不一致。


假设你有一个花哨的编译器,它的整数类型限制,如 limits.h 中所定义:

#define INT_MAX   2147483647   /* Typical 32-bit system value */
#define USHRT_MAX 2147483647   /* ***Edited***, original question had 2000000000 */

在我的应用程序中,我有以下代码:

unsigned short a = 1500000000;
unsigned short b = 1500000000;
unsigned short c;
c = a + b;

据我所知,最后一条指令会发生什么:

  1. a 上进行整体推广。由于int 可以接受unsigned short 的所有值,所以a 被提升为int
  2. 出于同样的原因,b 被提升为 int
  3. 添加发生在int 类型上。
  4. int 中无法表示结果。由于第 6.5/5 段的未定义行为。

我的推理正确吗?这真的会引发未定义的行为,还是我哪里出错了?请注意,我的代码仅适用于无符号类型,并且由于无符号类型的合法溢出,可能会出现对无符号整数应用模数的结果。

如果上一个问题的答案是“是的,未定义的行为”,那么这发生在符合法律要求的编译器上。那么,您能说我发布的应用程序代码不正确吗?是否所有非显式转换的小无符号整数加法都可能引发未定义的行为?

【问题讨论】:

  • 最简单的方法是如果sizeof(unsigned short) == sizeof(int)unsigned short 有一个填充位,而int 没有。在这种情况下,是的,添加两个 unsigned shorts 可以调用未定义的行为。
  • USHRT_MAX 2000000000 在 C 中是不可能的。无符号整数的最大值必须是 2 减一的幂。见 6.2.6.2.p1
  • 为什么两个相等类型的右值之间的相加需要提升?
  • @chux 重要的是INT_MAX == USHORT_MAX是完全可能的。
  • @Rhymoid 在 C 中,所有比 int 窄的类型都会在像 + 这样的操作之前被提升。

标签: c language-lawyer integer-promotion


【解决方案1】:

USHRT_MAX 不能定义为 2000000000。无符号整数的最大值必须为:2^n-1:

6.2.6.2 整数类型

  1. 对于 unsigned char 以外的无符号整数类型,对象的位 表示应分为两组:值位和填充位(需要 不是后者)。如果有 N 个值位,每个位应代表不同的 1 和 2 N-1 之间的 2 的幂,因此该类型的对象应能够 使用纯二进制表示表示从 0 到 2 N - 1 的值;这应该是 称为值表示。未指定任何填充位的值。

假设 USHRT_MAX 是 2^31-1,INT_MAX 是 2^31-1。

在这种情况下,变量 ab 将被提升为类型 int,由于整数提升,并且有符号加法的结果将溢出。

gcc 足够聪明,可以在将两个 unsigned short 变量的加法分配给 unsigned short 时将它们视为 unsigned。

不过,为了完全可移植,代码应该是:

c = a + 0u + b;

【讨论】:

  • @chux: 它仍然是 a 二次幂减一,而不是对应于sizeof(type)*CHAR_BIT 的二次幂。
  • @chux 它必须是 2^n-1,即使有填充位,因为填充位对值没有贡献。位要么是值位,要么根本不是。
  • @chux If there are N value bits, each bit shall represent a different power of 2 between 1 and 2 N−1 , so that objects of that type shall be capable of representing values from 0 to 2 N − 1 using a pure binary representation;
  • @chux:脚注 53:“填充位的某些组合可能会产生陷阱表示...... 所有其他填充位组合都是值位指定的值的替代对象表示。" 您引用的部分并不是说填充位 X 可能代表将 5 加到数字上;它是说填充位是设置还是未设置是未指定的。请注意,所使用的语言对位的和位表示的两个幂进行了区分。
  • @2501 同意可怕的说法。至少我认为uint32_ta+b 不会发生这种情况,因为int 不可能溢出。然而 a*b 可能会在 64 位 int 机器上溢出。
【解决方案2】:

无符号整数加法可以调用未定义的行为吗?

这取决于。

如果

  • int 的等级大于有问题的两个操作数(此处为unsigned short ints,因此在本例中为真) 李>
  • 有问题的两个操作数的值将适合int重要如果不是*1 em>
  • 算术运算(此处加法)会溢出

那么是的,这将调用 UB。

原因:

  1. 有问题的操作数(此处为 unsigned short ints)在算术运算中提升为 int(在 *1 的情况下不会)。
  2. ints 上的溢出算术运算调用 UB。

*1: 如果操作数 not 适合 int,则它会提升为 unsigned int,并且按照 2. 进行任何算术运算都会调用UB。

【讨论】:

  • 这似乎是正确的,无论看起来多么奇怪,unsigned short 都可能不适合 int。 (我已经投票了。)
  • @2501:根据标准,intshort int 可能具有相同的范围。在这种情况下,unsigned short int 可能不适合 int
猜你喜欢
  • 2014-04-01
  • 2015-01-16
  • 2011-11-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多