setjmp
+ longjmp
https://stackoverflow.com/a/25601100/895245 упомянул возможность или выдать исключение C ++ из обработчика сигнала, но Вызов исключения из обработчика сигнала упоминает несколько предостережений об этом, поэтому я буду очень осторожен.
В качестве другой потенциально опасной возможности вы также можете попытаться использовать более старый механизм C setjmp
+ longjmp
, как показано на: C обработать сигнал SIGFPE и продолжить выполнение
#include <csetjmp>
#include <csignal>
#include <cstring>
#include <iostream>
jmp_buf fpe;
void handler(int signum) {
longjmp(fpe, 1);
}
int main() {
volatile int i, j;
for(i = 0; i < 10; i++) {
struct sigaction act;
struct sigaction oldact;
memset(&act, 0, sizeof(act));
act.sa_handler = handler;
act.sa_flags = SA_NODEFER | SA_NOMASK;
sigaction(SIGFPE, &act, &oldact);
if (0 == setjmp(fpe)) {
std::cout << "before divide" << std::endl;
j = i / 0;
sigaction(SIGFPE, &oldact, &act);
} else {
std::cout << "after longjmp" << std::endl;
sigaction(SIGFPE, &oldact, &act);
}
}
return 0;
}
Скомпилируйте и запустите:
g++ -ggdb3 -O0 -std=c++11 -Wall -Wextra -pedantic -o main.out main.cpp
./main.out
Выход:
i = 0
before divide
after longjmp
i = 1
before divide
after longjmp
i = 2
before divide
after longjmp
man longjmp
говорит, что вы можете longjmp
из обработчиков сигналов, но с несколькими оговорками:
Техническое исправление POSIX.1-2008 2 добавляет longjmp () и siglongjmp () в список функций, безопасных для асинхронных сигналов. Тем не менее, стандарт рекомендует избегать использования этих функций от обработчиков сигналов и продолжает указывать
Выяснилось, что если эти функции вызываются из обработчика сигнала, который прервал вызов не асинхронно-безопасной функции сигнала (или некоторого эквивалента, такого как шаги, эквивалентные exit (3), которые происходят после возврата из начального
вызов main ()), поведение не определено, если программа впоследствии выполняет вызов не асинхронно безопасной для сигнала функции. Единственный способ избежать неопределенного поведения - обеспечить одно из следующих действий:
После долгого перехода из обработчика сигнала программа не вызывает никаких функций, не поддерживающих асинхронный сигнал, и не возвращает исходный вызов main ().
Любой сигнал, обработчик которого выполняет прыжок в длину, должен блокироваться при каждом вызове функции, не поддерживающей асинхронный сигнал, и никакие функции, не поддерживающие асинхронный сигнал, не вызываются после возврата из первоначального вызова в main ().
См. Также: Longjmp вне обработчика сигнала?
Однако Вызывая исключение из обработчика сигнала упоминает, что это еще более опасно для C ++:
setjmp и longjmp не совместимы с исключениями и RAII (ctors / dtors). :( Возможно, вы получите утечки ресурсов с этим.
так что вы должны быть очень, очень осторожны с этим.
Полагаю, мораль в том, что обработчики сигналов сложны, и вам следует избегать их как можно чаще, если вы точно не знаете, что делаете.
Обнаружение с плавающей точкой с нулевым делением
Также возможно обнаружить деление с плавающей запятой на ноль с помощью вызова glibc:
#include <cfenv>
feenableexcept(FE_INVALID);
как показано на: В чем разница между тихим NaN и сигнальным NaN?
Это вызывает повышение SIGFPE, а также целочисленное деление на ноль, а не просто молча qnan и установка флагов.