Вопрос про сигнал SIGFPE
СП - 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;
}
#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;
}
#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;
}
#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;
}
Помогите разобраться! :)
Может дело в неправильно написанном коде?
Или надо ключ какой-то при компиляции указать?
А может мой проц вообще такого делать не умеет (выдавать исключения при операциях с плавающей точкой) ?
все дело - в машинном представлении типа double. то, что написано в программе как 0.0 - внутри машины вовсе нулем не будет. соответственно и деления на 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;
}
#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;
}
очевидно, что система моя фиксирует деление на нуль с плавающей точкой. Мне же надо, чтобы она сигнализировала об этом сама! Чтоб мне не приходилось в ручную ставить проверки после каждой операции!
как насчет такого варианта?
Код:
#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;
}
#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, но, впринципе разницы быть не должно.
Я смотрел по стандарту с99, там про фукцию feenableexcept не сказано... Поэтому я ее пропустил )
Все супер, я только одного ...
Как сделать так, чтобы при возникновении сигнала и при выполнении обработчика, заданного мной, программа продолжала свое выполнение...
Т.е. если в вашей программе убрать exit(1); то программа зацикливается: строка "SIGFPE: floating point exception occured, exiting.\n" выводится бесконечное количество раз.
И почему не получается такой прием
Код:
signal(SIGFPE, SIG_IGN);