2

Stroustrup 说,在“C++ 的设计和演变”(Addison Wesley,1994 年)中,“假设算术溢出和除以零等低级事件由专用的低级机制处理,而不是由异常处理. 这使得 C++ 在算术方面能够与其他语言的行为相匹配。它还避免了在重流水线架构上发生的问题,例如除以零之类的事件是异步的。

Q1:如果不是异常,为什么GCC会报告一个而不是低级错误?

Q2:考虑到我正在除整数,为什么它报告为浮点数?

鉴于我无法用 catch(...) 捕捉到它,这是非常具有误导性的。显然我可以测试并避免整个“错误”,但我的观点是,对于认为它可能是异常(合理)、试图捕捉它、然后发现它不是异常的初学者来说,这非常令人困惑,并想知道报告的运行时异常。

我的编译器是 gcc 版本 4.2.1(Apple Inc. build 5666)(点 3)

对 CPU 异常、FPU 异常、语言异常和操作系统异常之间的区别进行一些准确的说明可能会解决此问题。

示例程序:

int main(){
    int i=1/0;
    return i;
}

结果输出:

浮点异常

4

4 回答 4

5

浮点异常 (FPE) 不是 C++ 异常。各种系统中有几种类型的异常,它们是不可互换的。FPE 在微处理器或 ISA 级别是一个例外,但在 C++ 级别不是。FPE 可能会触发一个名为 SIGFPE 的信号,您可以处理但不能使用 C++ try/catch。如果你想处理它,你可以使用 POSIX 函数 sigaction (我认为在 Windows 上会使用结构化异常处理)。

于 2012-02-20T18:21:06.230 回答
4

在 C++ 意义上,异常是软件检测到的错误。当您除以零时,它通常是检测问题的硬件并断言硬件异常(相同的名称,相似的概念,不同的野兽)。操作系统的硬件异常处理程序接收到这个并决定做什么。典型的操作系统反应是向硬件异常时正在运行的进程发送信号(如果系统在用户模式下运行),并让该进程的信号处理程序决定如何处理。

于 2012-02-20T18:18:32.043 回答
2

古代历史将浮点误差和除以零都折叠到 SIGFPE 中。虽然您可以在收到异常时对其进行解码以确定哪个异常,但 shell 不会。

于 2012-02-20T18:24:51.253 回答
1

下面的小程序捕获一个浮点错误并打印出有关信号的信息。请注意,从 C 语言的角度来看,除以零是未定义的行为。例如,并非所有系统都有 POSIX 信号。因为编译器可以简单地预测错误,它甚至可能在 POSIX 系统上决定简单地删除所有代码,或者立即退出并出现错误。(我希望并假设 POSIX 系统上的编译器会生成一个执行预期操作的程序。在它下面会执行此操作。但这种希望以前已经失望了。)

#include <stdio.h>
#include <signal.h>
#include <stdlib.h> // for exit()

void fpehandler (int sig, siginfo_t *info, void *uc) 
{
    fprintf (stderr, 
            "Caught signal no. %d; code: %d (FPE_INTDIV would be %d)\n", 
            sig, info->si_code, FPE_INTDIV);
    if(info->si_code == FPE_INTDIV)
    {
        fprintf (stderr, 
                "Yes, the error was an integer division by zero.\n");
    }

    // It's not officially safe to return from a handler
    // of a "program error signal" (of which SIGFPE is an example).
    // Plus many functions are not strictly safe to 
    // call in a signal handler (e.g. exit()).
    // See https://www.securecoding.cert.org/confluence/display/c/SIG30-C.+Call+only+asynchronous-safe+functions+within+signal+handlers .
    // We call _Exit().
    _Exit(0); // success, isn't it?
}

int main(void)
{
    struct sigaction sa;
    sigemptyset (&sa.sa_mask);
    sa.sa_flags = SA_SIGINFO;
    sa.sa_sigaction = fpehandler;
    sigaction (SIGFPE, &sa, NULL);

    // cause "floating point" error 
    printf("%d\n", 2/0);

    // ---- below is unreachable code ;-) ----------

    // We shouldn't be here. Something went wrong. return 1.
    return 1;            
}

当我在 cygwin、gcc 5.4.0 下运行它时,它会打印

$ gcc -Wall float-except.c -o float-except && ./float-except
float-except.c: In function 'main':
float-except.c:28:21: warning: division by zero [-Wdiv-by-zero]
     printf("%d\n", 2/0);
                     ^
Caught signal no. 8; code: 15 (FPE_INTDIV would be 15)
Yes, the error was an integer division by zero.
于 2016-10-25T16:57:42.577 回答