Ну, я искал статьи о SIGFPE, затем я написал несколько тестов, но их поведение странное. Тогда я должен опубликовать это здесь, чтобы попросить о помощи. Четко ли определены GCC / G ++ или ISO C ++, что происходит, если делить на ноль?
1) Я искал статью:
Деление на ноль не выбрасывает SIGFPE
это же вывод
2) Если я переписать это следующим образом:
void signal_handler (int signo) {
if(signo == SIGFPE) {
std::cout << "Caught FPE\n";
}
}
int main (void) {
signal(SIGFPE,(*signal_handler));
int b = 1;
int c = 0;
int d = b/c;
//fprintf(stderr,"d number is %d\n,d);
return 0;
}
тогда signal_handler не произойдет. но если я раскомментирую строку
//fprintf(stderr,"d number is %d\n,d);
Затем обработчик сигнала продолжает звонить.
может кто-то это объясняет?
Это интересно: с fprintf
закомментированный, компилятор определил, что вычисленный результат: d = b/c
является неиспользованным локальным выражением и может быть оптимизировано.
Очевидно, что при его исполнении он не свободен от побочных эффектов, но компилятор не может ничего определить относительно среды выполнения на данном этапе. Я удивлен, что статический анализ не воспринимает это как предупреждение (по крайней мере) в современном компиляторе.
@ Вонбранд прав. Вам повезло с тем, что вы делаете в (асинхронном) обработчике сигналов.
Редактировать: когда вы говорите «signal_handler продолжает звонить», вы имеете в виду, что он повторяется бесконечно? В этом случае могут возникнуть проблемы с перезапуском системных вызовов. Пытаться: siginterrupt(SIGFPE, 1);
(при условии, что это доступно).
В обработчиках сигналов разрешено только несколько операций, использующих любые буферизованные операции ввода-вывода (std::cout
и др., но также fprintf(3)
Который, кстати, я не знаю, хорошо ли он сочетается с предыдущим), не может быть и речи. Увидеть signal(7)
для ограничений.
Почему signal_handler не произойдет: оптимизация компилятора убила деление за неиспользованный результат.
Почему signal_handler продолжает вызывать: после возврата из обработчика сигнала FPE повторно выполняет ту же инструкцию. Вы можете избежать этого, используя longjmp.
Вот мой хорошо работающий код для этой цели (по крайней мере, в Mac OS X)
https://github.com/nishio/learn_language/blob/master/zero_division/zero_division.cpp
Четко ли определены GCC / G ++ или ISO C ++, что происходит, если делить на ноль?
Что касается стандарта, деление на ноль — это неопределенное поведение, все может произойти.
На практике, хотя в стандарте говорится, что это UB, он фактически определяется реализацией на уровне ОС (не языка / компилятора). В POSIX это действительно сгенерирует SIGFPE, в Windows он выдаст исключение (исключение SEH в Windows, а не исключение C ++, хотя некоторые компиляторы дополнительно отображают исключения SEH в C ++) и т. Д.
если я раскомментирую строку
//fprintf(stderr,"d number is %d\n,d);
Затем обработчик сигнала продолжает звонить. может кто-то это объясняет?
Как уже говорили другие, это потому, что компилятор обнаруживает, что d
никогда не используется и оптимизирует расчеты (а также b
а также c
определения по всей вероятности). Это происходит потому, что язык не может предвидеть, что произойдет (помните, это UB), поэтому он может предположить, что ничего не происходит.