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

att*_*rri 12 c integer-promotion language-lawyer

编辑:更改了值,USHRT_MAX因为它不符合注释所示.


想象一下,你有一个奇特的编译器,其limit.h中定义的整数类型限制是:

#define INT_MAX   2147483647   /* Typical 32-bit system value */
#define USHRT_MAX 2147483647   /* ***Edited***, original question had 2000000000 */
Run Code Online (Sandbox Code Playgroud)

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

unsigned short a = 1500000000;
unsigned short b = 1500000000;
unsigned short c;
c = a + b;
Run Code Online (Sandbox Code Playgroud)

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

  1. 整体推广a.由于int可以采取所有的价值unsigned short,a得到晋升int.
  2. 出于同样的原因,b晋升为int.
  3. 添加发生在int类型上.
  4. 结果无法表示int.由于第6.5/5段引起的未定义行为.

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

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

250*_*501 7

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,当它们被赋值给unsigned short时.

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

c = a + 0u + b;
Run Code Online (Sandbox Code Playgroud)

  • @chux:它仍然是*a*power-of-two减去1,而不是对应于`sizeof(type)*CHAR_BIT`的2的幂. (3认同)

alk*_*alk 6

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

这取决于.

如果

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

那么是的,这将调用UB.

原因:

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

*1:如果操作数并没有适合的int它被提升到unsigned int和任何与此运算按2以上就不会调用UB.