что делает C / C++ обработчик SIGFPE?

ну, я искал статьи о SIGFPE, затем я написал несколько тестов, но это странно. Тогда я должен отправить его сюда, чтобы попросить о помощи. Является ли GCC/g++ или ISO C++ четко определенным, что происходит, если разделить на ноль?

1) я искал статьи : деление на ноль не выбрасывает SIGFPE он выдает вывод inf

2) Если я перепишу его следующим образом:

void signal_handler (int signo) {
    if(signo == SIGFPE) {
      std::cout << "Caught FPEn";
    }
}

int main (void) {
  signal(SIGFPE,(*signal_handler));

  int b = 1;
  int c = 0;
  int d = b/c;
  //fprintf(stderr,"d number is %dn,d);
  return 0;
}

тогда signal_handler не произойдет. но если я раскомментируйте строку

//fprintf(stderr,"d number is %dn,d);

затем signal_handler продолжает звонить.

может кто-нибудь объяснить это ?

4 ответов


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

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

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


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


в обработчиках сигналов разрешено только несколько операций и использование любого буферизованного ввода-вывода (std::cout et al, но также 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); затем signal_handler продолжает звонить. кто-нибудь может это объяснить ?

как говорили другие, это потому, что компилятор обнаруживает, что d никогда не используется и оптимизирует расчет (а также b и c определения по всей вероятности). Это происходит потому, что язык не может предвидеть, что произойдет (помните, это UB), поэтому он можно ничего не считать, не происходит.