SIGFPE elkapása

 ( horvatha | 2005. május 4., szerda - 9:51 )

Hozzászólás megjelenítési lehetőségek

A választott hozzászólás megjelenítési mód a „Beállítás” gombbal rögzíthető.

[quote:e3a78fd042="Zahy"]Már miért is lepődtél meg? És meditor miért is írt (void *) -t? A signal handler nem tér vissza semmilyen értékkel - azaz (void) , tehát bármire mutató pointerrel sem tér vissza - márpedig tudtommal a (void *) ezt jelenti. Az már csak hab a tortán, h szerintem nem &fv, hanem csak simán fv, de ez már rég volt.[/quote:e3a78fd042]
Nem a void*-on, hanem h nem &fv... Mondjuk ezen majdnem mindig meglepődök (;

[quote:e2ab34e1e8="Zahy"]Már miért is lepődtél meg? És meditor miért is írt (void *) -t? A signal handler nem tér vissza semmilyen értékkel - azaz (void) , tehát bármire mutató pointerrel sem tér vissza - márpedig tudtommal a (void *) ezt jelenti. Az már csak hab a tortán, h szerintem nem &fv, hanem csak simán fv, de ez már rég volt.
És hogy közelebb legyek a topichoz, bár ez még így is off - az elmúlt kb 10 évben megírt szoftver lesz szíves nem használni a signal fv-t, helyette sigaction, sigblock, sigpause, sigpending, stb. Ja, goto POSIX.[/quote:e2ab34e1e8]

Képzeld el, nekem csak így fordul be: (void*)&routin
Isten bizony.

Úgyamúgy én jól elvagyok a signal-lal. A user1 a user2 a term, az int és az
alrm signálokat használom. Nem látom be, hogy miért ne lehetne
használni. Mi az ellenjavallat?

Ja még valami:

A (void *)&fv nem azt jelenti, hogy egy void pointerrel
visszatérő függvény, hanem azt, hogy a függvény CÍME
void azaz nincs típusa (határozatlan).

Kedves HUP-osok!

Valami primitív dolgot bénázok el, de nem sikerül elkapnom a hibás matematikai műveleteket C-ben. (Linux-2.6.11, gcc-3.4.3)

Azt szeretném, ha mondjuk negatív szmból gyököt vonok, az SIGFPE-t generálna és az el tudnám csípni. Azt hittem, a következő kód ezt megteszi:

---------------------
#include <stdio.h>
#include <signal.h>
void hiba()
{
printf("Lebegőpontos hiba!!\n");
}
void main()
{
float x,y;
signal(SIGFPE, hiba);
for (x=10.0; x>-10.0; x-=1.0)
{
y=sqrt(x);
printf("%f %f\n",x,y);
}
}
---------------------

Akárhogy próbálkozom, nem kapja el a hibás műveleteket, hanem szépen nan-okat írogat. Valamilyen fordítási opciót nem ismerek? (Próbálkoztam -mieee-fp -ftrapping-math -pal, de nem lett jobb tőle.)

Biztos valami primitív dolgot hibázok el, legyetek szívesek segíteni.

Illessz be egy printf("errno: %d\n", errno); sort az sqrt() hvása után (és egy #include <errno.h>-t előre).

[quote:9c4170af19="meditor"]
Úgyamúgy én jól elvagyok a signal-lal. A user1 a user2 a term, az int és az
alrm signálokat használom. Nem látom be, hogy miért ne lehetne
használni.[/quote:9c4170af19]

Egyetértek.
Fentebb idéztem az info-ból és mindenki a szintaktikára reagált, pedig csak azt akartam jelezni, hogy ANSI és POSIX, tehát tuti szabványos a signal fv.

No akkor elmagyarázom gyorsan. A signal hibája - [b:dfe0f88d87]ami egyébkélnt a linuxos man-ban szerepel is![/b:dfe0f88d87] -, hogy a SystemV és a BSD szemantika eltérő. Míg az eredeti AT&T-féle megszakításkezelés úgy működött, hogy ha beütött a megszakítás, akkor [b:dfe0f88d87]törlődött[/b:dfe0f88d87] a signalhandler beállítás (azaz újra ki kellett adni magában a handler rutinban a signal(...) hívást), addig a BSD szemantika szerint csak sorban áll a második szignál, és majd akkor kezeljük le, ha az eredeti lekezelésén már túl vagyunk. És túl azon, hogy ez nyilván különböző módon kezelendő le különböző rendszerekben, ezen túlmenően az eredeti AT&T-féle megoldás nem is megbízható, hiszen mikor becsap a megszakítás és elindul a signalhandler, majd befejeződik a benne szereplő signal() hívás - e kettő között bizony eltelik némi idő; no és ha itt - ebben a kis szünetben jön a következő megszakítás, akkor a progi lelkesen ki fog szállni (legalábbis a szignálok többségénél ugyebár ez az alapértelmezés).
Továbbiakban ajánlom pl. Richard W. Stevens: Advanced Programming in the UNIX Environment c. könyvét, vagy bármi hasonlót, ami részletesen taglalja a megszakításkezelést.
Persze annak, aki csak Linuxra ír programot (vagy [b:dfe0f88d87]csak[/b:dfe0f88d87] bármi egyébre), annak tök mindegy, de mi itt tudjuk, hogy pl. meditor azért használ motif-ot, mert hordozható. Amúgy pedig Linux alatt is lehet gáz, hisz mint úgyszintén a man-ból látszik, régebbi libc-kben az AT&T, újabbakban a BSD szemantika érvényes; ráadásul egy hülye preprocesszor makróval meg lehet a dolgot kavarni. Végül pedig idéznék a linux alatti signal maualból, a PORTABILITY szekcióból:
[b:dfe0f88d87]It is better to avoid signal altogether, and use sigaction(2) instead.[/b:dfe0f88d87]
Ez pedig ugyanaz, mint amit én korábban emlegettem.

Ui: meditor: amúgy kicsit furcsa, mert gcc -Wall -lal fordítva, abszolút semmit nem szólt, akár (void *) &fv -t írtam, akár mást. (pl. simán fv -t). (Sőt a lint se nyifogott egyik formára sem. Hihetetlen.)

[quote:0b65db81b1="sz"]Illessz be egy printf("errno: %d\n", errno); sort az sqrt() hvása után (és egy #include <errno.h>-t előre).[/quote:0b65db81b1]

Kösz, de nem ez kell nekem.

Az kellene, hogy ne kelljen egy kódba belenyúlnom, hanem csinálhassak egy rutint, ami matematikai hibakor meghívódik. Erre szolgálnának a signal-ok.

[quote:47b449456f="Zahy"]Végül pedig idéznék a linux alatti signal maualból, a PORTABILITY szekcióból:
[b:47b449456f]It is better to avoid signal altogether, and use sigaction(2) instead.[/b:47b449456f]
Ez pedig ugyanaz, mint amit én korábban emlegettem.
[/quote:47b449456f]

Köszi, ezt nem tudtam. Mindig tanul az ember valamit.
Bár az az igazság, hogy legtöbbet DJGPP-vel foglalkoztam, ha ez nem szentségtörés egy *NIX fórumon. :)

[quote="horvatha"][quote="sz"]Illessz be egy printf("errno: %d\n", errno); sort az sqrt() hvása után (és egy #include <errno.h>-t előre).[/quote]

Kösz, de nem ez kell nekem.

Az kellene, hogy ne kelljen egy kódba belenyúlnom, hanem csinálhassak egy rutint, ami matematikai hibakor meghívódik. Erre szolgálnának a signal-ok.[/quote]

kb 2 perc gugli:

http://rabbit.eng.miami.edu/info/functions/errors.html#mathsignal

[quote:d0682b2e25="horvatha"]Kösz, de nem ez kell nekem.

Az kellene, hogy ne kelljen egy kódba belenyúlnom, hanem csinálhassak egy rutint, ami matematikai hibakor meghívódik. Erre szolgálnának a signal-ok.[/quote:d0682b2e25]
Az egy dolog, h mi kellene neked (;

Az meg egy másik dolog, h az sqrt(-1) nem generál SIGFPE-t, csak "domain error"-t, amit az errno vizsgálatával tudsz ellenőrizni. Mitöbb, [i:d0682b2e25]double[/i:d0682b2e25] a = 10.0, b = 0.0; a/b; se generál SIGFPE-t. A kódod szignálkezelése egyébként (nagyjából) jó (lásd [i:d0682b2e25]int[/i:d0682b2e25] a = 10, b = 0; a/b; ), a gond az, h nincs szignál, amit lekezeljen.

[quote:04424a95fa="Zahy"]No akkor elmagyarázom gyorsan. A signal hibája - [b:04424a95fa]ami egyébkélnt a linuxos man-ban szerepel is![/b:04424a95fa] -, hogy a SystemV és a BSD szemantika eltérő. Míg az eredeti AT&T-féle megszakításkezelés úgy működött, hogy ha beütött a megszakítás, akkor [b:04424a95fa]törlődött[/b:04424a95fa] a signalhandler beállítás (azaz újra ki kellett adni magában a handler rutinban a signal(...) hívást), addig a BSD szemantika szerint csak sorban áll a második szignál, és majd akkor kezeljük le, ha az eredeti lekezelésén már túl vagyunk. És túl azon, hogy ez nyilván különböző módon kezelendő le különböző rendszerekben, ezen túlmenően az eredeti AT&T-féle megoldás nem is megbízható, hiszen mikor becsap a megszakítás és elindul a signalhandler, majd befejeződik a benne szereplő signal() hívás - e kettő között bizony eltelik némi idő; no és ha itt - ebben a kis szünetben jön a következő megszakítás, akkor a progi lelkesen ki fog szállni (legalábbis a szignálok többségénél ugyebár ez az alapértelmezés).
Továbbiakban ajánlom pl. Richard W. Stevens: Advanced Programming in the UNIX Environment c. könyvét, vagy bármi hasonlót, ami részletesen taglalja a megszakításkezelést.
Persze annak, aki csak Linuxra ír programot (vagy [b:04424a95fa]csak[/b:04424a95fa] bármi egyébre), annak tök mindegy, de mi itt tudjuk, hogy pl. meditor azért használ motif-ot, mert hordozható. Amúgy pedig Linux alatt is lehet gáz, hisz mint úgyszintén a man-ból látszik, régebbi libc-kben az AT&T, újabbakban a BSD szemantika érvényes; ráadásul egy hülye preprocesszor makróval meg lehet a dolgot kavarni. Végül pedig idéznék a linux alatti signal maualból, a PORTABILITY szekcióból:
[b:04424a95fa]It is better to avoid signal altogether, and use sigaction(2) instead.[/b:04424a95fa]
Ez pedig ugyanaz, mint amit én korábban emlegettem.

Ui: meditor: amúgy kicsit furcsa, mert gcc -Wall -lal fordítva, abszolút semmit nem szólt, akár (void *) &fv -t írtam, akár mást. (pl. simán fv -t). (Sőt a lint se nyifogott egyik formára sem. Hihetetlen.)[/quote:04424a95fa]

Na akkor egy friss házielemzés:

1. Ami a signal-t illeti én minden egyes megszakítási rutinban
figyelem, hogy végrehajtása közben jön-e be újabb ugyanolyan
megszakítás. Ez még mikrokontroller-assembly-s koromból ragadt
rám, és soha nem bántam meg, hogy ezt a módszert alkalmaztam.

Abban igazad van, hogy néha lehetne korszerűbben is
szemlélni a dolgokat, de ha van egy jól bevált, sok-sok év alatt
fejlesztett rutingyűjteményed nem szívesen cseréled le.

2. a szintaxisról: signal(SIG,fv) - Ha fv=

Proba - incompatible pointer type
Proba() - invalid use of void expression
(void*)Proba() - void value not ignored
void * Proba - pars error before void
(void*)Proba - ez O.K.
(void*)&Proba - ez is O.K.

A két utolsó eset ekvivalens egymással, az egyik sem
jobb vagy rosszabb a másiknál.

Ja! -Wall, bár megjegyzem hogy az első négy eset error-ral
áll le.

3. A motif & signal: Ha át kellene írnom a signálkezelést egy
másfajtára, legfeljebb 1-2 nap. De egy grafikát átírni több hónap.
Tehát az én kicsi világomban a grafika hordozhatósága SOKKAL
lényegesebb, mint egy nem időkritikus (rendszerint: TERM,
INT, USER1, USER2, ALRM) signal kezelése.

Sehol nem állítottam, hogy tökéletes programokat írok. (másfelöl
programfagyás, segfault, specifikációtól eltérő működés nem
fordul elő, pedig igencsak nyúzzák őket)

[quote:bf5adddc9f="meditor"]
2. a szintaxisról: signal(SIG,fv) - Ha fv=

Proba - incompatible pointer type
Proba() - invalid use of void expression
(void*)Proba() - void value not ignored
void * Proba - pars error before void
(void*)Proba - ez O.K.
(void*)&Proba - ez is O.K.

A két utolsó eset ekvivalens egymással, az egyik sem
jobb vagy rosszabb a másiknál.
[/quote:bf5adddc9f]

Nekem a signal(SIG,Proba) forma még warningot sam adott!
Legalábbis úgy emléxem.

[quote:f23b60c7b5="begyu"][quote:f23b60c7b5="meditor"]
2. a szintaxisról: signal(SIG,fv) - Ha fv=

Proba - incompatible pointer type
Proba() - invalid use of void expression
(void*)Proba() - void value not ignored
void * Proba - pars error before void
(void*)Proba - ez O.K.
(void*)&Proba - ez is O.K.

A két utolsó eset ekvivalens egymással, az egyik sem
jobb vagy rosszabb a másiknál.
[/quote:f23b60c7b5]

Nekem a signal(SIG,Proba) forma még warningot sam adott!
Legalábbis úgy emléxem.[/quote:f23b60c7b5]

Nálam: Linux Slackware 10.0, gyári gcc. Amúgy azt gondolom, hogy a
(void*)&Proba formának mindenhol kötelessége befordulni.

csak érdekességképpen fűzném hozzá, hogy az eskimo.com (amit ugye mind ismertek :)) idevágó passzusa az alábbi helyen található:

http://www.eskimo.com/~scs/cclass/int/sx10a.html

(csak azoknak akiket érdekel mert újak C-ben, azok akik már sokat használtak funct pointereket azok már mindezt úgyis tudják)

[quote:a2663781fc="horvatha"]
Akárhogy próbálkozom, nem kapja el a hibás műveleteket, hanem szépen nan-okat írogat. Valamilyen fordítási opciót nem ismerek? (Próbálkoztam -mieee-fp -ftrapping-math -pal, de nem lett jobb tőle.)

Biztos valami primitív dolgot hibázok el, legyetek szívesek segíteni.[/quote:a2663781fc]

Szia!

[code:1:a2663781fc]
#include <math.h>
#include <errno.h>
#include <signal.h>
#include <setjmp.h>

jmp_buf entry;

extern int errno;

double errcheck();
execerror();

void fpecatch()
{
execerror("floating point exception", (char *)0);
}

void init()
{
setjmp(entry);
signal(SIGFPE, fpecatch);
}

double Log(x)
double x;
{
return errcheck(log(x), "log");
}

double Sqrt(x)
double x;
{
return errcheck(sqrt(x), "sqrt");
}

double Exp(x)
double x;
{
return errcheck(exp(x), "exp");
}

warning(s, t)
char *s, *t;
{
fprintf(stderr, "%s", s);
if (t)
fprintf(stderr, " %s", t);
}

execerror(s, t)
char *s, *t;
{
warning(s, t);
fseek(fin, 0L, SEEK_END);
longjmp(entry, 0);
}

double errcheck(d, s)
double d;
char *s;
{
if (errno == EDOM) {
errno = 0;
execerror(s, "argument out of domain");
} else if (errno == ERANGE) {
errno = 0;
execerror(s, "result out of range");
}
return d;
}

[/code:1:a2663781fc]

Ez csak egy példa, de a lényeg benne van.

Bocs,[code:1:62ff8c3153]fseek(fin, 0L, SEEK_END); [/code:1:62ff8c3153] ez benne maradt.
Nem tartozik a témához.

[quote:99af81a5ab="horvatha"]Kedves HUP-osok!

Valami primitív dolgot bénázok el, de nem sikerül elkapnom a hibás matematikai műveleteket C-ben. (Linux-2.6.11, gcc-3.4.3)

Azt szeretném, ha mondjuk negatív szmból gyököt vonok, az SIGFPE-t generálna és az el tudnám csípni. Azt hittem, a következő kód ezt megteszi:

---------------------
#include <stdio.h>
#include <signal.h>
void hiba()
{
printf("Lebegőpontos hiba!!\n");
}
void main()
{
float x,y;
signal(SIGFPE, hiba);
for (x=10.0; x>-10.0; x-=1.0)
{
y=sqrt(x);
printf("%f %f\n",x,y);
}
}
---------------------

Akárhogy próbálkozom, nem kapja el a hibás műveleteket, hanem szépen nan-okat írogat. Valamilyen fordítási opciót nem ismerek? (Próbálkoztam -mieee-fp -ftrapping-math -pal, de nem lett jobb tőle.)

Biztos valami primitív dolgot hibázok el, legyetek szívesek segíteni.[/quote:99af81a5ab]

Tippjeim:

1. signal(SIGFPE, (void*)&hiba);
2. Biztos, hogy SIGFPE keletkezik?
3. man sigprocmask

[quote:56196990e6="meditor"]1. signal(SIGFPE, (void*)&hiba);[/quote:56196990e6]
Én is meglepődtem rajta, de nem.
http://www.gnu.org/software/libc/manual/html_node/Basic-Signal-Handling.html

Már miért is lepődtél meg? És meditor miért is írt (void *) -t? A signal handler nem tér vissza semmilyen értékkel - azaz (void) , tehát bármire mutató pointerrel sem tér vissza - márpedig tudtommal a (void *) ezt jelenti. Az már csak hab a tortán, h szerintem nem &fv, hanem csak simán fv, de ez már rég volt.
És hogy közelebb legyek a topichoz, bár ez még így is off - az elmúlt kb 10 évben megírt szoftver lesz szíves nem használni a signal fv-t, helyette sigaction, sigblock, sigpause, sigpending, stb. Ja, goto POSIX.

[quote:8cf2f6a063="Zahy"]Már miért is lepődtél meg? És meditor miért is írt (void *) -t? A signal handler nem tér vissza semmilyen értékkel - azaz (void) , tehát bármire mutató pointerrel sem tér vissza - márpedig tudtommal a (void *) ezt jelenti. Az már csak hab a tortán, h szerintem nem &fv, hanem csak simán fv, de ez már rég volt.
És hogy közelebb legyek a topichoz, bár ez még így is off - az elmúlt kb 10 évben megírt szoftver lesz szíves nem használni a signal fv-t, helyette sigaction, sigblock, sigpause, sigpending, stb. Ja, goto POSIX.[/quote:8cf2f6a063]

Hi!
Ez szerepel a libc infojában:
[quote:8cf2f6a063]
void (*signal(int sig, void (*func)(int)))(int);

Portability:
ANSI/ISO C C89; C99
POSIX 1003.2-1992; 1003.1-2001
[/quote:8cf2f6a063]

[quote:df5b7edbf1="begyu"]
Hi!
Ez szerepel a libc infojában:
[quote:df5b7edbf1]
void (*signal(int sig, void (*func)(int)))(int);

Portability:
ANSI/ISO C C89; C99
POSIX 1003.2-1992; 1003.1-2001
[/quote:df5b7edbf1][/quote:df5b7edbf1]
Örülök neki. És megemlíteném, hogy a void (*func)(int) - az nem csak az én olvasatomban, de azt jelenti, hogy:
1) void -ot ad vissza - tehát nem ad vissza semmit
2) (*func) tehát ez a (2.) paramétere a signal fv-nek egy fv-pointer
3) (int) - amely fv egyébként egy db. int tipusú változót vár paraméternek.

De ha gondoljátok, az egészet lefordítom. Tehát:
void - a signal maga nem ad vissza semmit
(*signal ...)() - a signal-nak nevezett fv-re mutató pointer-ről beszélünk (gy.k. ez maga a signal nevű fv)
(int sig, ...) - a signal első paramétere, ami int
( ..., void (*func)(int) ) - a signal második paramétere egy értéket vissza nem adó fv-re mutató pointer, amely fv egy int -et vár paraméterként - ahogy azt fentebb már leírtam

Szóval megemlíteném, hogy a
void (*fv)
és a
void * (fv)
között azért van egy kis apró, nüansznyi különbség.
De ez kb C-programozás 4. 5. óra lehet (nekünk anno az _első_ C-specin a ponterekre mutató pointerek kétdimenziós tömbjét vágták a fejünkhöz, holott többségünk életében nem látott még akkor egyáltalán C-t semmit).
No elmentem, jó kis C alapok tanulást a nap hátralevő részére!

Ezt lehetne kipróbálni:

/* matherr.c */

#include <fenv.h>
#include <math.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>

static void hiba (int signo)
{
    char tmp[256];
    int len;

    len= sprintf (tmp, ">>> Lebegőpontos hiba signo=%d\n", signo);
    write (2, tmp, len);
    _exit (1);
}

int main (void)
{
    float x,y;

    signal (SIGFPE, (void (*)(int))hiba);
    feenableexcept (FE_DIVBYZERO | FE_UNDERFLOW | FE_OVERFLOW | FE_INVALID);

    for (x= 10.0; x>-10.0; x-=1.0) {
	y=sqrt(x);
	printf("%f %f\n",x,y);
	fflush (stdout);
    }

    return 0;
}

off: gyors válasz trolloknak: igen, látom hogy régi a topik
gyors válasz programozóknak: ha jól látom, sajnos nem POSIX