2013-02-16 11 views
6

bene, ho cercato gli articoli su SIGFPE, poi ho scritto alcuni test ma il comportamento è strano. Quindi devo postarlo qui per chiedere aiuto. GCC/G ++ o ISO C++ definiscono chiaramente cosa succede se dividi per zero?cosa gestisce SIGFPE C/C++?

1) I cercato l'articolo: Division by zero does not throw SIGFPE esso Sameš l'uscita è inf

2) Se riscrivo come la seguente:

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; 
} 

poi signal_handler no succede. ma se decommento la riga

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

quindi signal_handler continua a chiamare.

qualcuno può spiegarlo?

+0

Integer divisione per zero solleva ancora 'SIGFPE' (errore di virgola mobile), ma floating point divisione per zero cede l'infinito come risposta. –

+0

'int c = 0; int d = b/c; '? che significa 'b/0'? – billz

+0

Non ti riproduco in modo esatto: ottengo il segnale solo una volta e poi il programma termina, con o senza 'printf'. Se aggiungo il segnale '(SIGFPE, (* signal_handler));' all'interno del gestore del segnale, quindi vi riproduco. Linux 3.10, gcc 4.7.3. –

risposta

5

Questo è interessante: con il fprintf commentato, il compilatore ha determinato che il risultato calcolato: d = b/c è un'espressione locale non utilizzata e può essere ottimizzato.

Chiaramente, non è privo di effetti collaterali nella sua esecuzione, ma il compilatore non può determinare nulla sull'ambiente di runtime in questa fase. Sono sorpreso che l'analisi statica non lo prenda come avvertimento (almeno) in un compilatore moderno.

@vonbrand ha ragione. Sei stato fortunato con quello che stai facendo nel gestore di segnale (asincrono).


Edit: quando si dice "signal_handler continua a chiamare", vuoi dire che è la ripetizione all'infinito? In tal caso, potrebbero verificarsi problemi con il riavvio delle chiamate di sistema sottostanti. Prova: siginterrupt(SIGFPE, 1); (ammesso che sia disponibile).

3

Ci sono solo alcune operazioni consentite nei gestori di segnale e l'utilizzo di qualsiasi I/O con buffer (std::cout e così via, ma anche fprintf(3), che BTW non so se si confonde bene con il precedente) è esaurito la domanda. Vedi signal(7) per le restrizioni.

1

GCC/G ++ o ISO C++ definiscono chiaramente cosa succede se dividi per zero?

Per quanto riguarda lo standard, la divisione per zero è Comportamento indefinito, qualsiasi cosa potrebbe accadere.

In pratica, anche se lo standard dice che è UB, in realtà è definito dall'implementazione a livello di sistema operativo (non di lingua/compilatore). Su POSIX questo sarà davvero generare un SIGFPE, su Windows sarà un'eccezione (eccezione SEH Windows', non è un'eccezione C++, anche se alcuni compilatori inoltre mappa SEH di eccezioni C++), ecc

se togliere il commento alla linea //fprintf(stderr,"d number is %d\n,d); quindi signal_handler continua a chiamare. qualcuno può spiegarlo?

Come altri hanno detto, questo è perché il compilatore rileva che d mai è utilizzato e ottimizza via il calcolo (come pure i b e c definizioni di cui con ogni probabilità). Questo accade perché la lingua non può prevedere cosa accadrà (ricorda, è UB) quindi potrebbe anche non succedere nulla.

3

Perché signal_handler non accadrà: ottimizzazione del compilatore ha ucciso la divisione per il risultato non utilizzato.

Perché signal_handler continua a chiamare: Dopo il ritorno dal gestore di segnale, FPE esegue nuovamente la stessa istruzione. Puoi evitarlo usando longjmp.

Ecco il mio codice ben lavorare per lo scopo (almeno su Mac OS X) https://github.com/nishio/learn_language/blob/master/zero_division/zero_division.cpp

+0

Sembra funzionare anche su 'g ++' e' clang ++ 'su' ubuntu' – ubershmekel

Problemi correlati