【问题标题】:No Runtime error after divison by zero除以零后没有运行时错误
【发布时间】:2015-06-05 05:35:18
【问题描述】:

我正在使用 Microsoft Visual C++ 2010 我有以下代码,如您所见,我将 1 除以零

#include <cstdio>

int main()
{   
   int x;
   x = 0;
   1/x;

   while (1) {
      std::printf("RUNNING!!\n");
   }
}

令人惊讶的是,我没有发现任何运行时错误,程序继续执行并显示 RUNNING!!

所以我的问题是为什么“1/x”不被认为是运行时错误,为什么程序不会停止?

【问题讨论】:

  • @hacks:不,我不认为that 是重复的。甚至,操作数的类型也截然不同!而这次的原因不同……
  • @LightnessRacesinOrbit;不是和精确的欺骗,而是“非常接近”。
  • @hacks:但还不够接近,因为问题代码和答案根本不同。

标签: c++ visual-studio-2010 visual-c++ runtime-error runtimeexception


【解决方案1】:

作为对其他所有人的补充,我注意到一些关于“获取或不获取运行时错误”的 cmets,这让我想到了对模棱两可的术语的误解。

在普通计算机科学中,“运行时错误”不再是人类大脑的计算机语言(简单的英语)的含义:而是在“程序执行”期间发现的错误。

所以是的,在信号后从操作系统获取转储是“运行时错误”。至少对于英语来说。

但这与std::runtime_error 有关,即std::exception 当错误出现在他们自己的代码中时,由标准库(或任何其他基于标准库的代码)抛出 /em>。

“异常”一词也含糊不清:在操作系统术语中,它是“救援代码”,一个适当的操作系统驱动程序用于响应 CPU 硬件陷阱。在 C++ 中,is 要么是表示所有标准库错误的基类,要么是 throw 语句的任何值主题。

这里的重点是,整数除以零不是标准库实现检测到的错误:C++ 语言将基本整数算术视为宿主环境的原语。在大多数平台中,operator/(int,int) 是通过 DIV 汇编指令(至少在大多数 CPU 上)实现的,并且带有 0 操作数的 DIV 由 CPU 微码作为 CPU 异常处理,这会产生“陷阱”(或由操作系统(或特定操作系统驱动程序)处理的中断,或任何平台术语所称的中断。 C++ 编译器(和生成的可执行文件)中没有任何东西知道 DIV 评估期间发生了什么(因为它在 CPU 内部),所以没有可以编写的 throw 语句,并且因此没有要捕获的 std::exception (或任何其他 C++ 类型)。只是一个可以替换的操作系统驱动程序,默认情况下会终止应用程序。

这与调用 main(调用 exit)的 C++ 启动代码中的等效默认 catch(...) 非常相似,因此是另一个混​​淆来源。

更复杂的是,编译器优化可以丢弃任何不会产生使用结果的操作,从而使所有内容变得不可见。

所以,输出除法结果是必须的,让编译器不会丢弃操作。完成后,会观察到产生 OS 信号的 CPU 陷阱。这是 - 用简单的英语表示“运行时错误”,但不是 C++ std::runtime_error,因为除法运算符实现中不存在这样的 throw 语句。

【讨论】:

    【解决方案2】:

    来自笔记

    Stroustrup 在“C++ 的设计和演变”中说(Addison Wesley, 1994),“低级事件,例如算术溢出和除 零,假定由专用的低级机制处理 而不是例外。这使 C++ 能够匹配 算术方面的其他语言。它也避免了 在大量流水线架构上发生的问题,其中事件 例如除以零是异步的。"`


    所以我的问题是为什么“1/x”不被视为运行时错误

    您没有将 1/x 的值分配给任何变量,因此您会遇到任何运行时错误。将它分配给一个变量,你会得到一个运行时错误。

    【讨论】:

    • 这只是解释了为什么除以零不会导致 C++ 级别的异常,并且部分是这样。
    • @LightnessRacesinOrbit:- 谢谢。更新了我的答案!
    • @LightnessRacesinOrbit:- 是的,因为这是唯一丢失的部分,可能是正确答案;)
    【解决方案3】:

    您没有将1/x 的评估分配给另一个变量。这就是您没有收到运行时错误的原因。

    如果你像这样修改你的代码 -

    int r;
    r = 1/x;
    

    然后程序因错误而停止。

    【讨论】:

    • 你可能还需要使用 r.
    • 我刚刚在 ubuntu 12.04 中使用 gcc 版本 4.6.3 运行了该程序。它给了我错误而没有进一步使用r,错误是-Floating point exception (core dumped)。但我认为这将是运行时异常。
    • SIGFPE 和核心转储不是运行时错误的原因是什么?你还期待什么?
    【解决方案4】:

    相反,为什么您认为应该是运行时错误?没有规定必须这样做。

    除以零是未定义。在这种情况下,由于它可能在编译时被捕获,您的编译器似乎只是忽略了该操作……很可能是因为您从未使用过它的“结果”。

    所以,这个程序运行并且可能什么也不输出:

    int main()
    {
        int x = 0;
        1/x;
    }
    

    而我可以预期 this 程序会导致系统级算术异常:

    #include <iostream>
    
    int main()
    {
        int x = 0;
        int y = 1/x;
    
        std::cout << y << '\n';
    }
    

    一般来说,当您有未定义的行为时,不要期待任何事情。不要指望你的程序“工作”,不要指望它产生有意义的输出,不要指望它不会打电话给你的前妻并撤销你对宠物鸡的合法监护权,也不要指望它会导致你想要的错误。

    【讨论】:

    • 所以,在使用它的结果的情况下,我已经尝试过了,程序停止并显示未处理异常的消息,这被认为是“运行时错误”还是其他什么?
    • 感谢 Lightness,我想知道我的鸡去哪儿了,当然,我的代码中除以零了。
    猜你喜欢
    • 2013-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-30
    相关资源
    最近更新 更多