【问题标题】:Is it possible to access the overflow flag register in a CPU with C++?是否可以使用 C++ 访问 CPU 中的溢出标志寄存器?
【发布时间】:2013-01-16 12:52:12
【问题描述】:

在执行数学运算后,例如,将两个整数相乘,是否可以使用 C++ 访问 CPU 中的溢出标志寄存器?如果不是,还有什么其他快速检查溢出的方法?

【问题讨论】:

  • @acrilige 谢谢,这回答了我问题的第二部分,关于如何在执行计算后检查溢出的任何想法?
  • 由于显而易见的原因,不可能以标准的可移植方式直接访问溢出标志寄存器。但是,您可以通过一些工作来确定操作是否会溢出,并且有一些方法可以检查这一点或以非标准的非便携方式检测溢出。
  • 为什么不能在计算前检查溢出?
  • 将结果除以被乘数。如果你没有得到乘数,那么它就会溢出。

标签: c++ assembly flags integer-overflow


【解决方案1】:

不,通常这是不可能的。有些 CPU 甚至没有这样的标志(例如 MIPS)。

其中一个 cmets 中提供的 link 将为您提供有关如何进行溢出检查的想法。

请记住,在 C 和 C++ 中,有符号整数溢出会导致未定义的行为,并且在法律上您不能在事后执行溢出检查。您要么需要使用无符号算术,要么在算术运算之前进行检查。

【讨论】:

    【解决方案2】:

    我建议在每个适当的情况下阅读此书。来自Optimizing software in C++ -

    整数溢出是另一个安全问题。官方 C 标准 表示有符号整数在溢出情况下的行为是 “不明确的”。这允许编译器忽略溢出或假设 它不会发生。在 Gnu 编译器的情况下,假设 没有发生有符号整数溢出是不幸的 结果是它允许编译器优化溢出 查看。针对这个问题有许多可能的补救措施: (1) 在溢出发生之前检查溢出,(2) 使用无符号整数 - 他们保证环绕,(3)陷阱整数溢出 选项-ftrapv,但是这样效率极低,(4)获取编译器 带有选项的此类优化警告 -Wstrict-overflow=2,或 (5) 使用选项明确定义溢出行为 -fwrapv-fno-strict-overflow

    【讨论】:

      【解决方案3】:

      您必须执行该操作并检查内联汇编中的溢出位。您可以这样做并在溢出时跳转到标签,或者(更普遍但效率较低)在溢出时设置一个变量。

      【讨论】:

      • 奇怪的是没有其他人提到这个选项。虽然内联汇编并不是严格意义上的 C++,但对于任何提出这个问题的人来说,它绝对是一个可行的选择。当然,它不会为所有架构都编译存在限制,但这取决于 OP 来决定这是否重要。
      【解决方案4】:

      没有。提前检查的最佳方法here

      如果不是,还有什么其他快速检查溢出的方法?

      如果您需要在运算后进行测试,您可以使用浮点表示(双精度) - 每个 32 位整数都可以完全表示为浮点数。 如果您所针对的所有机器都支持 IEEE(如果您不必考虑大型机,可能就是这种情况),您可以只执行操作,然后在结果上使用 isfinite 或 isinf。 快速(就程序员的努力而言)方式是:IEEE 浮点算术标准 (IEEE 754) 定义了五个异常,每个异常都返回一个默认值并具有相应的状态标志(在某些下溢情况下除外)发生异常时引发。 五个可能的例外是:

      • 无效运算:数学上未定义,例如,负数的平方根。默认情况下,返回 qNaN。
      • 除以零:对有限操作数的运算给出精确的无限结果,例如 1/0 或 log(0)。默认情况下,返回 ±infinity。
      • 溢出:结果太大而无法正确表示(即,其具有无限指数范围的指数将大于 emax)。默认情况下,对于最近舍入模式返回 ±infinity(并遵循有向舍入模式的舍入规则)。
      • 下溢:结果非常小(超出正常范围)且不精确。默认情况下,返回次正规或零(遵循舍入规则)。
      • 不精确:精确(即未四舍五入)结果无法精确表示。默认情况下,返回正确舍入的结果。

      【讨论】:

      • 请注意,这个问题被标记为integer-overflow 并且是关于有符号整数溢出的。不是 FP 溢出到 +-Inf。您可以通过fenv: en.cppreference.com/w/c/numeric/fenv 访问FP 标志。 fetestexcept(FE_OVERFLOW) 检查 FP 溢出标志。 (仅当您使用 #pragma STDC FENV_ACCESS ON 或某些编译器的命令行选项时才能正常工作。en.cppreference.com/w/c/numeric/fenv/fetestexcept 有一个示例。)
      • 我明白了 - 每个整数都可以表示为浮点数,没有其他快速方法。除了提前检查。
      • double 可以代表每个int32_t,但不能代表每个int64_t。所以是的,您可以在转换回int 之前检查double 的范围。这几乎没有效率,所以 IDK 你的意思是什么。有些机器会有一个 80 位或更宽的 long double,可以代表每个 int64_t,但许多 C++ 实现只有 64 位 FP。此外,FP 溢出与此问题无关(除非您进行多次实际产生 FP 溢出的乘法)。
      • 双精度浮点数限制为 10^308。超过 10^64。 IEEE 754 是关于单精度和双精度的。
      • 是的,这是最大的有限 double,但第一个不可表示的整数值 double 是 2^53 + 1,因为它有一个 53 位尾数。 en.wikipedia.org/wiki/Double-precision_floating-point_format。一个 64 位的double 可以表示除int64_t 的可能值之外的一些数字,因此根据鸽巢原理,必须有一些int64_t 的值没有double 位模式来表示它们。见Which is the first integer that an IEEE 754 float is incapable of representing exactly?
      【解决方案5】:

      这可能不是您想要做的,原因有两个:

      1. 并非每个 CPU 都有溢出标志
      2. 使用 C++ 实际上没有办法访问溢出标志

      人们之前发布的溢出检查提示可能很有用。

      如果您真的想非常快速地编写将两个整数相乘并检查溢出标志的代码,您将不得不使用汇编。如果您想要一些 x86 的示例,请询问

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-03-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-22
        • 2011-09-03
        • 2013-06-24
        • 1970-01-01
        相关资源
        最近更新 更多