【问题标题】:Arithmetic overflow in C++17C++17 中的算术溢出
【发布时间】:2018-10-15 15:11:30
【问题描述】:
  1. 对于uint8_tuint16_tuint32_tuint64_t,是否根据 C++17 定义了算术溢出?如果是,定义的行为是什么(非常感谢 C++ 标准的摘录)
  2. 对于int8_tint16_tint32_tint64_t,是否根据 C++17 定义了算术溢出? (非常感谢 C++ 标准的摘录)
  3. 如果以上任何一项或全部是特定于实现的,g++ 和 clang 的定义是什么?
  4. 如果它是特定于架构的(正如 Havenard 指出的那样),我的问题是特定于 x86(-64)。
  5. 如果我做更小的 unsigned int - 更大的 unsigned int,它的定义是否明确?

我看到post 的第一个答案提到我的问题 #1,它是在 C 标准中定义的,尽管他没有引用它,我在 C++ 标准中找不到任何相关内容。

==================

更新 1:

删除了每个 ach 的“下溢”,因为它是错误的术语(感谢@ach)。添加了 #5 来表达我所说的“下溢”的真正含义(不正确)

【问题讨论】:

  • 什么都没有改变 unsgined 整数上溢/下溢定义明确,signed 没有。
  • 它是特定于架构的,它不是由语言决定的。
  • 关于术语的注释:不存在整数算术下溢。下溢仅适用于浮点运算。当计算结果的绝对值小于可表示的结果时,就会发生这种情况。
  • @HCSF 通常,这是溢出。但在 C/C++ 的情况下,这是常规算术;它定义明确;我自己称之为环绕,但我完全不确定这个词是否合适。
  • @HCSF 你错过了我的观点:从一般计算机科学的角度来看,这是溢出 - 算术运算产生的值无法在目标类型中表示。但是 C 和 C++ 明确定义了对无符号整数的运算是模数运算,所以溢出是不可能的。

标签: c++ x86 g++ clang language-lawyer


【解决方案1】:

为了创建一个规范,这里有一些规范规范(引自最新的 C++ 草案):

  • 无符号整数不会溢出:参见 6.7.1:

无符号整数应遵循算术模 2n 的定律,其中 n 是该特定值表示中的位数 整数的大小。 (44) 这意味着无符号算术不 溢出,因为结果不能由结果表示 无符号整数类型以大一的数为模减少 比结果可以表示的最大值 无符号整数类型。

  • 有符号整数上溢/下溢未定义:参见 7.1.4:

如果在计算表达式期间,结果不是 数学定义或不在可表示值的范围内 它的类型,行为未定义。

顺便说一句,它们都不是特定于实现的,编译器会积极利用上溢/下溢进行优化。例如,如下 sn-p 所示:

void a();
void b();

void foo(int k) {
    int z = k+1;
    if (z < k) {
        a();
    } else {
        b();
    }
}

https://gcc.godbolt.org/z/0re-nM - 分支被消除,即使在真实平台上由于模 2 表示,z 实际上可能变得小于 k

【讨论】:

  • 感谢您的回复。我之前也读过 6.7.1。但我不清楚“比最大的山谷大一个”的实际含义。那么对于uint32_t,maxuint32_t+1就是4294967296,应该怎么表示呢? “减少模数”是什么意思?向左移动位?还是?
  • 我刚刚看了你的例子。您正在使用有符号整数进行演示,这属于第 7.1.4 节指出的未定义行为。没有?
  • 基本上在您的示例中,z 保证等于 k 就在 if 语句中,因为它们肯定是相同的(即使 ++k 未定义),所以编译器可以安全地消除我认为的分支。
  • 由于 ++k 溢出将是 UB,编译器可以假设它永远不会发生。所以 z == k+1 一直都在删除分支。
  • 既然问题也是关于小类型的,你需要以某种方式提到整数提升......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多