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

时间:2016-05-27 15:53:09

标签: c language-lawyer integer-promotion

修改:更改USHRT_MAX的值,因为它不符合评论所示。

想象一下,你有一个奇特的编译器,其整数类型限制,如 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段引起的未定义行为。
  5. 我的推理是否正确?这是否真的会调用未定义的行为,或者我哪里出错了?请注意,我的代码仅适用于无符号类型,并且由于无符号类型的合法溢出,可能会出现对无符号整数应用模数的结果。

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

2 个答案:

答案 0 :(得分:7)

USHRT_MAX无法定义为2000000000.无符号整数的最大值必须采用以下格式:2 ^ n-1:

  

6.2.6.2整数类型

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

假设USHRT_MAX为2 ^ 31-1且INT_MAX为2 ^ 31-1。

在这种情况下,由于整数提升,变量ab将被提升为int类型,并且签名添加的结果将会溢出。

gcc非常聪明,可以将两个无符号短变量添加为unsigned,当它们被赋值为unsigned short时。

然而,为了完全可移植性,代码应该是:

c = a + 0u + b;

答案 1 :(得分:6)

  

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

这取决于。

如果

  • int的等级大于有问题的两个操作数(unsigned short int s,所以在这种情况下这是真的)
  • 有问题的两个操作数的值将适合int(如果不是 * 1 那么重要的极角情况)
  • 算术运算(此处加法)将溢出

然后是的,这将调用UB。

原因:

  1. 有问题的操作数(此处unsigned short int)在算术运算中被提升为int(在 * 1 的情况下,他们不会获胜)。
  2. int上的溢出算术运算调用UB。
  3. * 1: 如果操作数 适合int,它会被提升为unsigned int,并且根据上面的任何算术运算将 调用UB。 功能