сигналы — что делает C / C ++ обработчик SIGFPE?

Ну, я искал статьи о 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);

Затем обработчик сигнала продолжает звонить.

может кто-то это объясняет?

6

Решение

Это интересно: с fprintf закомментированный, компилятор определил, что вычисленный результат: d = b/c является неиспользованным локальным выражением и может быть оптимизировано.

Очевидно, что при его исполнении он не свободен от побочных эффектов, но компилятор не может ничего определить относительно среды выполнения на данном этапе. Я удивлен, что статический анализ не воспринимает это как предупреждение (по крайней мере) в современном компиляторе.

@ Вонбранд прав. Вам повезло с тем, что вы делаете в (асинхронном) обработчике сигналов.


Редактировать: когда вы говорите «signal_handler продолжает звонить», вы имеете в виду, что он повторяется бесконечно? В этом случае могут возникнуть проблемы с перезапуском системных вызовов. Пытаться: siginterrupt(SIGFPE, 1); (при условии, что это доступно).

5

Другие решения

В обработчиках сигналов разрешено только несколько операций, использующих любые буферизованные операции ввода-вывода (std::cout и др., но также fprintf(3)Который, кстати, я не знаю, хорошо ли он сочетается с предыдущим), не может быть и речи. Увидеть signal(7) для ограничений.

3

Почему signal_handler не произойдет: оптимизация компилятора убила деление за неиспользованный результат.

Почему signal_handler продолжает вызывать: после возврата из обработчика сигнала FPE повторно выполняет ту же инструкцию. Вы можете избежать этого, используя longjmp.

Вот мой хорошо работающий код для этой цели (по крайней мере, в Mac OS X)
https://github.com/nishio/learn_language/blob/master/zero_division/zero_division.cpp

3

Четко ли определены 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), поэтому он может предположить, что ничего не происходит.

1
По вопросам рекламы [email protected]