Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Вопрос про сигнал SIGFPE

35K
04 января 2009 года
Aleshka
9 / / 03.05.2008
ОС - kubuntu 7.10
СП - gcc
Проц - celeron d420 (x86)
Язык программирования - C

Подскажите, почему cигнал SIGFPE генерируется моей программой только если происходит целочисленное деление на 0.

Этот сигнал ведь должен генерироваться и при делении на 0 с плавающей точкой, и при переполнении с плавающей точкой и еще в некоторых случаях. ( смотри, например, http://ru.wikipedia.org/wiki/SIGFPE). Так почему же он не генерируется после такой вот строки
 
Код:
double a=1.0/0.0;


Например, в следующем примере строка "Exception was taken. si_code = " не выводится:

Код:
#include <signal.h>
#include <stdio.h>

void siga(int signo, siginfo_t *info, void *context)
{
  printf("Exception was taken. si_code = %d\n", info->si_code);
  pause();
}

struct sigaction act, oact;

int main(){
  sigemptyset(&act.sa_mask);
  act.sa_flags = SA_SIGINFO;
  act.sa_sigaction = &siga;

  sigaction(SIGFPE, &act, &oact);
  double a=1.0/0.0;

  return 0;
}


Или вот попроще (тоже строка "Exсeption was taken\n" не выводится) :

 
Код:
#include <signal.h>
#include <stdio.h>

void hey(){printf("Exсeption was taken\n");}

int main(){
signal(SIGFPE, hey);
double a=1.0/0.0;
return 0;
}


А в этом случае строка "Exсeption was taken\n" будет вылетать бесконечное количество раз:

Код:
#include <signal.h>
#include <stdio.h>

void hey(){printf("Exсeption was taken\n");}

int main(){
signal(SIGFPE, hey);
int a, b, c;
a=1; b=0;
c=a/b;
return 0;
}


Помогите разобраться! :)
Может дело в неправильно написанном коде?
Или надо ключ какой-то при компиляции указать?
А может мой проц вообще такого делать не умеет (выдавать исключения при операциях с плавающей точкой) ?
2
04 января 2009 года
squirL
5.6K / / 13.08.2003
все дело - в машинном представлении типа double. то, что написано в программе как 0.0 - внутри машины вовсе нулем не будет. соответственно и деления на 0 нет.
35K
04 января 2009 года
Aleshka
9 / / 03.05.2008
Не утверждаю про все платформы, но на моей 0.0 - это как раз 0 (по ieee 754 нуль с плавающей точкой - это когда все биты мантисы и все биты порядка равны 0, у меня как раз так)

Флаг, отвечающий за ошибку деления на нуль с плавающей точкой, у меня устанавливается! Вот пример:
Код:
#include <stdio.h>
#include <fenv.h>

#pragma STDC FENV_ACCESS ON

void divbyzero(){ printf("DIVIDE BY ZERO EXCEPTION\n"); }


int main(){
  int set_excepts;
  feclearexcept(FE_ALL_EXCEPT); /*очищаем все флаги, отвечающие за исключения при вычислениях с плав. точкой*/
  set_excepts = fetestexcept(FE_ALL_EXCEPT); /* установим в переменной set_excepts текущее состояние флагов */
  /*если в переменной set_excepts флаг, отвечающий за деление на нуль с плав. точкой, установлен, то вызываем функцию divbyzero();*/
  if (set_excepts & FE_DIVBYZERO) divbyzero(); //пока деления не было, так что функция не вызывается
  double a=1.0/0.0; //произошло деление на нуль с плав. точкой
  set_excepts = fetestexcept(FE_ALL_EXCEPT); /*опять установим текущее состояние флагов в переменную set_excepts*/
  if (set_excepts & FE_DIVBYZERO) divbyzero(); /* деление было, так что функция divbyzero будет вызывана */
 
  return 0;
}


очевидно, что система моя фиксирует деление на нуль с плавающей точкой. Мне же надо, чтобы она сигнализировала об этом сама! Чтоб мне не приходилось в ручную ставить проверки после каждой операции!
2
04 января 2009 года
squirL
5.6K / / 13.08.2003
и что? в этой программе обработка деления на "вещественный" нуль выполняется не системой, а библиотечными функциями. вы бы уж man fenv до конца дочитали бы :)

как насчет такого варианта?
Код:
#include <stdio.h>
#include <fenv.h>
#include <signal.h>
#include <stdlib.h>

void fpehandler(int sig_num)
{
        signal(SIGFPE, fpehandler);
        printf("SIGFPE: floating point exception occured, exiting.\n");
        exit(1);
}

int main()
{
        double x, y;

        int feenableexcept();
        feenableexcept(FE_ALL_EXCEPT);
        signal(SIGFPE, fpehandler);

        x= 0.0;
        y= 0.0;

        x= x/y;
}

правда на Linux не проверял, проверял на FreeBSD, но, впринципе разницы быть не должно.
35K
04 января 2009 года
Aleshka
9 / / 03.05.2008
Спасибо! то что надо было!
Я смотрел по стандарту с99, там про фукцию feenableexcept не сказано... Поэтому я ее пропустил )

Все супер, я только одного ...
Как сделать так, чтобы при возникновении сигнала и при выполнении обработчика, заданного мной, программа продолжала свое выполнение...
Т.е. если в вашей программе убрать exit(1); то программа зацикливается: строка "SIGFPE: floating point exception occured, exiting.\n" выводится бесконечное количество раз.

И почему не получается такой прием
 
Код:
signal(SIGFPE, SIG_IGN);
То есть чтоб программа игнорировала сигнал SIGFPE...
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог