【问题标题】:What rules in C11 standard determine the evaluation of `int tx = INT_MAX +1`?C11 标准中的哪些规则决定了 `int tx = INT_MAX +1` 的评估?
【发布时间】:2020-10-16 22:15:20
【问题描述】:
  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中的哪些规则决定了这一步的转换是如何进行的?

【问题讨论】:

  • C11 6.5p5: "如果在计算表达式的过程中出现异常情况(即,如果结果没有在数学上定义或不在其类型的可表示值范围内) , 行为未定义"

标签: c type-conversion integer c11


【解决方案1】:

INT_MAX1 都具有 int 类型,因此结果将具有 int 类型。执行此操作会导致有符号整数溢出,即undefined behavior

Section 3.4.3p3 给出了一个未定义行为的例子:

示例 未定义行为的一个示例是整数溢出行为。

【讨论】:

  • 如果语句只有INT_MAX +1;,而不是int tx = INT_MAX +1;,结果是int还是更大的类型?
  • @Tim 结果类型永远不会超过 2 个操作数
  • @phuclv:将char 添加到char 会生成int
  • @Tim 这是一种可能的结果,但标准不保证一定会发生。使用不同的编译器或不同的设置可能会产生不同的结果。
  • @Tim:问题的标题是“C11 标准中有哪些规则……” GCC 的行为不是 C11 标准中的规则。是的,GCC 的行为并非巧合; GCC 的设计具有 C 标准之外的许多属性,包括基于模糊记忆的可选选项来包装有符号整数算术。但这不是 C11 标准中的规则。
【解决方案2】:

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

如果在计算表达式期间出现异常情况(即,如果结果未在数学上定义或不在其类型的可表示值范围内),则行为未定义。

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


您可以通过将代码更改为int tx = INT_MAX + 1u; 来强制转换。这里一个操作数1uunsigned int 类型。因此通常的算术转换INT_MAX 转换为unsigned int 类型(参见Implicit type promotion rules)。结果是定义明确的2147483648unsigned int 类型。

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

否则,新类型是有符号的,值不能在其中表示;无论是 结果是实现定义的或引发了实现定义的信号。

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


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

【讨论】:

猜你喜欢
  • 2010-10-21
  • 1970-01-01
  • 1970-01-01
  • 2014-12-16
  • 2015-11-20
  • 1970-01-01
  • 2015-01-13
  • 1970-01-01
  • 2019-09-07
相关资源
最近更新 更多