zoukankan      html  css  js  c++  java
  • How to Capture the Integer-Divide-By-Zero Error in C++(提前定义信号)

    How to Capture the Integer-Divide-By-Zero Error in C++?

    MANUAL CAPTURE

    The simple and straightforward method is to check it manually if possible. The following outputs “got you!”.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    
    // https://helloacm.com
    #include <iostream>
    using namespace std;
     
    int main() {
        try {
            int x = 1, y = 0;
            if (y == 0) {
                    throw "error"; 
            }
            cout << x / y;
        } catch (...) {
            cerr << "got you!";
        }
        return 0;
    }

    However, it is tedious and not-so-elegant to place checks at each possible code occurrence and we want to the program to handle this.

    TRY-CATCH DOES NOT CATCH INT-DIVIDE-BY-ZERO ERROR

    The first thought would be to put the possible divide-by-zero code in side a try-catch, like this:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    
    // https://helloacm.com
    #include <iostream>
    using namespace std;
     
    int main() {
        try {
            int x = 1, y = 0;
            cout << x / y;
        } catch (...) {
            cerr << "got you!";
        }
        return 0;
    }

    However, when you compile the above code using g++ compiler and run it, the error says Floating point exception instead of the customize error message in try-catch. This means that the error is not caught by try-catch.

    USING SIGNAL

    At Linux, we can set up signals to capture the error. In this case, the error type is SIGFPE which stands for Signal Float Point Exceptions. The function to set up a signal is signal and it takes two parameters, the signal type and the function to handle.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    
    // https://helloacm.com
    #include <iostream>
    #include <cstdlib>
    #include <csignal>
     
    using namespace std;
     
    void error(int) {
        cerr << "got you!";
        exit(1);
    }
     
    int main() {
        if (SIG_ERR == signal(SIGFPE, error)) {
            cerr << "failure to setup signal.";
            return 1;
        }
        int x = 1, y = 0;
        cout << x / y;
        return 0;
    }

    In short, the when SIGFPE signal is caught, the error function will be invoked to deal with the error. The exit(1) function is important here. In case if you just simply return from the error-handling-function, the disaster happens with an endless loop, which prints “got you!” repeatedly until you ctrl+C to abort/kill it.

    When error happens, the OS call the stack of the error function, and set its return address just right before the int-div-by-zero. Virtually, the error-function is invoked right before the error occurs. And after the error-function returns, it will again meet the code that triggers the error, which is why it will keep printing the error.

    Some might’ve thought to fix this by making the y variable the global and set to 1 inside the error function. However, this does not help. It seems that the error still occurs regardless the value of y.

    1
    2
    3
    4
    5
    6
    
    // https://helloacm.com
    int y = 0; // global variable
    void error(int) {
        cerr << "got you!";
        y = 1; // set to 1 to fix it, but this does not work, why?
    }

    USING EXCEPTIONS

    We could easily replace above exit() with the exceptions to throw in the error function:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    
    // https://helloacm.com
    #include <iostream>
    #include <cstdlib>
    #include <csignal>
     
    using namespace std;
    struct div_0_exception {};
     
    void error(int) {
        throw div_0_exception();
    }
     
    int main() {
        if (SIG_ERR == signal(SIGFPE, error)) {
            cerr << "failure to setup signal.";
            return 1;
        }
        try {
            int x = 1, y = 0;
            cout << x / y;
        } catch (div_0_exception) {
            cout << "got you!";
        }
        return 0;
    }

    USING CUSTOMIZED SIGNAL

    The above throws regardless the type of float point exceptions. The POSIX defines a more comprenhensive signal processing interface, i.e. sigaction, which is defined in csignal header.

    1
    2
    3
    4
    5
    6
    7
    
    // https://helloacm.com
    struct sigaction;
     
    int sigaction(int sig,
                  struct sigaction const* restrict act,
                  struct sigaction* restrict old_act
    );

    Please note that, these two have the same identifies. The first one is the structure type that stores some function pointers. And the second is the actual function entry to set up the signal. The third parameter is usually set to NULL, for more information, read man 3 sigaction.

    The sigaction structure has two function entry points:

    1
    2
    
    void (* sa_handler)(int);
    void (* sa_sigaction)(int, siginfo_t*, void*);

    The first entry is the light-weight handling method, which has been shown in previous code examples. The second one allows more information in the code context. Based on the second parameter, we could pass the additional information via sa_flags. Possible si_code values: FPE_INTOVF (integer overflow), FPE_FLTUND (float underflow), FPE_FLTOVF (float overflow) and what we care about – the FPT_INTDIV.

    Let’s look at the complete example of C++ using comprehensive signal to catch the integer-divided-by-zero error.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    
    // https://helloacm.com
    #include <iostream>
    #include <cstdlib>
    #include <csignal>
     
    struct my_sig_action {
        typedef void (* handler_type)(int, siginfo_t*, void*);
     
        explicit my_sig_action(handler_type handler)
        {
            memset(&_sa, 0, sizeof(struct sigaction));
            _sa.sa_sigaction = handler;
            _sa.sa_flags = SA_SIGINFO;
        }
     
        operator struct sigaction const*() const
        {
            return &_sa;
        }
    protected:
        struct sigaction _sa;
    };
     
    struct div_0_exception {};
     
    void error(int sig, siginfo_t* info, void*) {
        if (FPE_INTDIV == info->si_code)
            throw div_0_exception();
    }
     
    int main()
    {
        my_sig_action sa(error);
        if (0 != sigaction(SIGFPE, sa, NULL)) {
            cerr << "failure to setup signal.";
            return 1;
        }
        try {
            int x = 1, y = 0;
            cout << x / y;
        } catch (div_0_exception) {
            cout << "got you!";
        }
        return 0;
    }

    –EOF (The Ultimate Computing & Technology Blog) —

    https://helloacm.com/how-to-capture-the-integer-divide-by-zero-error-in-c/

  • 相关阅读:
    elementUI 表格分页后台排序记录
    oracle乱码记录
    JavaScript 数字转汉字+element时间选择器快速选择
    js中call()方法和apply方法的使用
    Rails导出CSV
    CakePHP2.x 发送邮件
    一个例子说明substr(), mb_substr() 和 mb_strcut()之间的区别
    substr是不安全的
    CakePHP中回调函数的使用
    cakephp中find('list')的使用
  • 原文地址:https://www.cnblogs.com/findumars/p/6371861.html
Copyright © 2011-2022 走看看