C11 标准中的哪些规则决定了 `int tx = INT_MAX +1` 的评估?

What rules in C11 standard determine the evaluation of `int tx = INT_MAX +1`?

  int tx = INT_MAX +1; // 2147483648;                                                                                                                                                 
  printf("tx = %d\n", tx);

打印 tx = -2147483648.

我想知道如何解释基于 C11 标准中的 6.3 转换的结果?

  1. 计算INT_MAX +1时,两个操作数都是int吗?结果是2147483648long int吗? 6.3 中的哪条规则决定了结果的类型?

  2. 在计算 tx = ... 时,右侧位表示的高位是否被截断,以便其大小从 long int 大小变为 int大小,然后截断的结果是否解释为 int? 6.3 中的哪些规则决定了这一步中的转换是如何完成的?

INT_MAX1 的类型都是 int,所以结果的类型是 int。执行此操作会导致有符号整数溢出,即 undefined behavior.

第 3.4.3p3 节将此作为未定义行为的示例:

EXAMPLE An example of undefined behavior is the behavior on integer overflow.

这里的相关部分是6.5/5:

If an exceptional condition occurs during the evaluation of an expression (that is, if the result is not mathematically defined or not in the range of representable values for its type), the behavior is undefined.

发生这种情况是因为 INT_MAX 和整数常量 1 都具有类型 int。所以你根本做不到INT_MAX + 1。并且没有隐含的 promotions/conversions 存在来挽救这一天,因此 6.3 不适用。这是一个错误,任何事情都可能发生。


您可以做的是通过将代码更改为 int tx = INT_MAX + 1u; 来强制转换。这里的一个操作数 1uunsigned int 类型的。因此,通常的算术转换INT_MAX 转换为类型unsigned int(参见)。结果是 well-defined 2147483648 类型 unsigned int.

然后尝试将其存储在 int tx 中,转换为赋值的左操作数,然后 6.3 的转换规则生效。特别是 6.3.1.3/3:

Otherwise, the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised.

因此,通过将类型更改为 1u,我们将代码从未定义更改为 impl.defined 行为。仍然不理想,但至少现在代码在给定的编译器上具有确定性行为。理论上,结果可能是 SIGFPE 信号,但实际上所有 real-world 2 的补码 32/64 位编译器都可能给你结果 -2147483648.


具有讽刺意味的是,我听说过的所有 real-world 2 的补码 CPU 都以确定性方式执行有符号溢出。因此,C 的未定义行为部分只是 C 标准的人为构造,是由允许奇异的 1 的补码和带符号幅度格式的无用语言功能引起的。在这种奇特的格式中,有符号溢出可能导致陷阱表示,因此 C 必须声明整数溢出是未定义的行为,即使它不在 C 程序正在执行的 real-world 2 的补码 CPU 上上。