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/

posted @   findumars  Views(1128)  Comments(0Edit  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
历史上的今天:
2015-02-06 关于delphi Assigned
2015-02-06 Apache HTTP Server安装
点击右上角即可分享
微信分享提示