为什么该标准必须解决除零问题?

use*_*462 8 c++ compiler-construction divide-by-zero

我试图理解下面的代码res1之间的区别:res2

#include <iostream>

int main()
{   
    int x = 1;
    int y = 0;
    
    double res1 = double(x)/y;      // OK: evaluates to Inf
    int res2 = x/y;                 // run-time error: Floating point exception
    // 1/0;                         // g++ warning: division by zero [-Wdivision-by-zero]  
    
    std::cout << res1;
    
    return 0;
}

Run Code Online (Sandbox Code Playgroud)

据我了解,除以零是 C++ 标准中未定义的行为,并且res1和之间存在差异的原因res2是由于我的机器为 实现了 IEEE 754 double,它需要除以零才能返回Inf-Inf

但现在我想知道为什么标准必须首先对除以零做出任何声明。这个答案说它是为了适应实现 C++ 的各种不同的体系结构,但我不确定 -除以零不是更多的运行时问题吗?特别是如果编译器在大多数情况下不太可能在不评估分母的情况下检测到它(我认为这就是上面示例中发生的情况)。当然,如果我尝试类似 的操作1/0,那么 g++ 会发出警告,但在大多数情况下,我们期望分母是一个更复杂的表达式。

Tom*_*sen 3

据我了解您想知道的问题,为什么明确声明除以零是未定义的,而不是完全从标准中忽略它?在这里,我认为从标准中省略某些内容与指定某些内容未定义之间存在重要区别。

\n

关于表达式的求值,我们感兴趣的本质是 \xc2\xa75.4:

\n
\n

\xc2\xa75.4
\n如果在计算表达式期间,结果未在数学上定义或不在其类型的可表示值范围内,则行为未定义。[ 注意:大多数现有的 C++ 实现都会忽略整数溢出。除以零的处理、使用零除数形成余数以及所有浮点异常因机器而异,并且通常可以通过库函数进行调整。\xe2\x80\x94 尾注]

\n
\n

资料来源:https ://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3797.pdf

\n

如果标准中没有包含此声明,则读者的解释基本上是相同的。因此,读者必须找出极端情况的存在,并且它会导致未定义的行为。

\n

在 C++ 标准中,由于其他原因,未定义行为也很重要,特殊规则适用于未定义行为,例如由 \xc2\xa75.19(常量表达式)定义的 \xe2\x80\x94 以及其他 \xe2\ x80\x94 声明:

\n
\n

条件表达式 e核心常量表达式,除非 的计算e遵循抽象机 (1.9) 的规则,将计算以下表达式之一:
\n...
\n\xe2\x80\x94 一个操作,该操作将具有未定义的行为[注意:包括例如有符号整数溢出(第 5 条)、某些指针算术(5.7)、除以零(5.6)或某些移位操作(5.8)\xe2\x80\x94 尾注]

\n
\n

因此,了解某些内容何时未定义对于 C++ 标准的读者来说非常重要。

\n

除以零需要是未定义行为的另一个原因正如您所提到的,它发生在运行时。如果它有定义的行为(它可以),编译器将必须处理所有整数除法运算,并用除零处理来包装它们。由于处理器可能会以不同的方式处理除零,并且 C++ 作者不想在处理这种情况时增加开销,因此他们故意声明它是未定义的。

\n

因此,在某种程度上,您可以说这是一个运行时问题,但编译器生成执行运行时行为的代码,并且除以零有可能破坏正常的执行范围,并且在以下方面很重要语言的其他方面(请参阅上面有关常量表达式的评论),因此需要对其进行定义。但还有其他未定义的事情,您可以说是“运行时问题”整数溢出。作为一名开发人员,我喜欢了解发生的情况,以及我是否可以对给定情况下发生的情况做出任何假设。对于整数溢出,我可能会期望特定的行为是合乎逻辑的,因为它在我的架构上以特定的方式运行。在这方面,我希望我的标准能够指导我期待什么,不期待什么。

\n