简体   繁体   English

为什么GCC在执行1/0时会报告浮点异常?

[英]Why does GCC report a Floating Point Exception when I execute 1/0?

Stroustrup says, in "The Design and Evolution of C++" (Addison Wesley, 1994), "low-level events, such as arithmetic overflows and divide by zero, are assumed to be handled by a dedicated lower-level mechanism rather than by exceptions. This enables C++ to match the behaviour of other languages when it comes to arithmetic. It also avoids the problems that occur on heavily pipelined architectures where events such as divide by zero are asynchronous." Stroustrup在“C ++的设计和演变”(Addison Wesley,1994)中说,“低级事件,例如算术溢出和除以零,假设由专用的低级机制而不是异常处理这使得C ++能够在算术运算时匹配其他语言的行为。它还避免了在流水线严重的体系结构中出现的问题,其中除以零之类的事件是异步的。

Q1: If it's not an exception, why does GCC report one as opposed to a lower-level error? Q1:如果不是例外,为什么GCC会报告一个而不是一个较低级别的错误?

Q2: Given I'm dividing integers, why is it reported as floating point ? Q2:鉴于我正在划分整数,为什么报告为浮点数?

Given I cannot catch it with catch(...), it is very misleading. 鉴于我无法用catch(...)来捕捉它,这是非常误导的。 Obviously I can test and avoid the whole 'error', but my point is that it is very confusing for a beginner who thinks that it might be an exception (reasonable), tries to catch it , then finds out that it's NOT AN EXCEPTION , and wonders about the run-time exception reported. 显然我可以测试并避免整个'错误',但我的观点是,对于一个认为它可能是异常(合理)的初学者来说,它是非常混乱的,试图抓住它,然后发现它不是异常,并且对报告的运行时异常感到奇怪。

My compiler is gcc version 4.2.1 (Apple Inc. build 5666) (dot 3) 我的编译器是gcc版本4.2.1(Apple Inc. build 5666)(第3点)

Some accurate clarification of the difference between CPU exceptions, FPU exceptions, Language exceptions and OS exceptions might resolve this. 准确澄清CPU异常,FPU异常,语言异常和操作系统异常之间的区别可能会解决这个问题。

Example Program: 示例程序:

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

Resulting Output: 结果输出:

Floating point exception 浮点异常

A floating-point exception (FPE) is not a C++ exception. 浮点异常(FPE)不是C ++异常。 There are several types of exceptions in various systems, and they are not interchangeable. 各种系统中有几种类型的例外,它们不可互换。 An FPE is an exception at the microprocessor or ISA level, but not at the C++ level. FPE是微处理器或ISA级别的例外,但不是C ++级别的例外。 An FPE may result in the firing of a signal called SIGFPE, which you can handle but not using C++ try/catch. FPE可能会导致触发一个名为SIGFPE的信号,您可以处理但不使用C ++ try / catch。 If you want to handle it you can use the POSIX function sigaction (I think on Windows one would use Structured Exception Handling). 如果你想处理它,你可以使用POSIX函数sigaction(我认为在Windows上会使用结构化异常处理)。

Exceptions, in the C++ sense, are software-detected errors. 在C ++意义上,例外是软件检测到的错误。 When you divide by zero, its typically the hardware that detects the issue and it asserts a hardware exception (same name, similar concept, different beast). 当除以零时,它通常是检测问题的硬件,并且它断言硬件异常(同名,类似概念,不同的野兽)。 The operating system's hardware exception handler receives this and decides what to do. 操作系统的硬件异常处理程序接收此内容并决定要执行的操作。 A typical OS reaction is to send a signal to the process that was running at the time of the hardware exception (if the system was running in user mode), and let that process's signal handler decide how to handle things. 典型的OS反应是向硬件异常时运行的进程发送信号(如果系统在用户模式下运行),并让该进程的信号处理程序决定如何处理事情。

Ancient history folded both floating point error and division by zero into SIGFPE. 古代历史将浮点误差和零除以SIGFPE。 While you can on receiving the exception decode it to determine which, the shell doesn't. 虽然你可以在接收异常时解码它以确定哪个,但shell没有。

The following little program catches a floating point error and prints out information about the signal. 以下小程序捕获浮点错误并打印出有关信号的信息。 Note that from a C language standpoint a division by zero is undefined behavior. 请注意,从C语言的角度来看,除以零是未定义的行为。 For example, not all systems have POSIX signals. 例如,并非所有系统都具有POSIX信号。 Because the compiler can trivially predict the error, it may even on POSIX systems decide to simply eliminate all code, or exit immediately with an error. 因为编译器可以简单地预测错误,所以甚至可以在POSIX系统上决定简单地消除所有代码,或者立即退出错误。 (I would hope and assume that a compiler on POSIX systems will produce a program which does the expected thing. Below it does. But such hopes have been disappointed before.) (我希望并假设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;            
}

When I run it under cygwin, gcc 5.4.0, it prints 当我在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.

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM