2013-02-16 11 views
6

cóż, przeszukałem artykuły o SIGFPE, następnie napisałem kilka testów, ale jego zachowanie jest dziwne. Następnie muszę opublikować to tutaj, aby poprosić o pomoc. Czy GCC/G ++ lub ISO C++ jasno określają, co się stanie, jeśli podzielimy przez zero?co robi program obsługi C/C++ SIGFPE?

1) Szukałem artykuł: Division by zero does not throw SIGFPE sames to wyjście jest inf

2) Gdybym przepisać jak:

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

następnie signal_handler nie będzie się dzieje. ale jeśli odkomentuję linię, wtedy signal_handler będzie nadal wywoływał.

Czy ktoś może to wyjaśnić?

+0

Integer dzielenie przez zero, nadal budzi 'SIGFPE' (floating point error), ale zmiennoprzecinkowych dzielenie przez zero daje nieskończoność jako odpowiedź. –

+0

'int c = 0; int d = b/c; '? co oznacza "b/0"? – billz

+0

Nie reprodukuję cię tylko: Otrzymuję sygnał tylko raz, a następnie program wychodzi, z lub bez 'printf'. Jeśli dodaję 'signal (SIGFPE, (* signal_handler));' wewnątrz procedury obsługi sygnału, to ja odtwarzam. Linux 3.10, gcc 4.7.3. –

Odpowiedz

5

To jest interesujące: po skomentowaniu fprintf kompilator ustalił, że obliczony wynik: d = b/c jest nieużywanym wyrażeniem lokalnym i można go zoptymalizować.

Oczywiście, nie jest to efekt wolny od efektów ubocznych, ale na tym etapie kompilator nie może ustalić niczego na temat środowiska wykonawczego. Jestem zaskoczony, że analiza statyczna nie wybiera tego jako ostrzeżenia (przynajmniej) w nowoczesnym kompilatorze.

@vonbrand ma rację. Miałeś szczęście z tym, co robisz w (asynchronicznej) procedurze obsługi sygnału.


Edit: kiedy mówisz "signal_handler trzyma Calling", masz na myśli to powtarzać w nieskończoność? Jeśli tak, mogą wystąpić problemy z ponownym uruchomieniem wywołań systemowych. Wypróbuj: siginterrupt(SIGFPE, 1); (zakładając, że jest dostępny).

3

Dostępnych jest tylko kilka operacji w modułach obsługi sygnałów, a użycie dowolnego buforowanego wejścia/wyjścia (std::cout i innych, ale także fprintf(3), którego BTW nie wiem, czy dobrze się miesza z poprzednim) jest poza pytanie. Zobacz signal(7) dla ograniczeń.

1

Czy GCC/G ++ lub ISO C++ są jasno zdefiniowane, co się stanie, jeśli podzielimy przez zero?

Jeśli chodzi o standard, dzielenie przez zero jest niezdefiniowanym zachowaniem, wszystko może się zdarzyć.

W praktyce, nawet jeśli standard mówi, że jest UB, jest on faktycznie zdefiniowany przez implementację na poziomie systemu operacyjnego (nie języka/kompilatora). Na POSIX będzie to rzeczywiście wygenerować SIGFPE, Windows będzie to wyjątek (wyjątek SEH Windows', a nie C++ wyjątek choć niektóre kompilatory dodatkowo mapowania SEH wyjątków C++), itd

gdybym odkomentować linia //fprintf(stderr,"d number is %d\n,d); następnie signal_handler ciągle dzwoni. Czy ktoś może to wyjaśnić?

Jak mówili inni, to dlatego, że kompilator wykryje, że d nigdy nie jest używany i optymalizuje dala obliczeń (jak również bc definicje i według wszelkiego prawdopodobieństwa). Dzieje się tak, ponieważ język nie może przewidzieć, co się stanie (pamiętaj, to UB), więc równie dobrze może się wydawać, że nic się nie dzieje.

3

Dlaczego signal_handler się nie dzieje: optymalizacja kompilatora zabiła podział na nieużywany wynik.

Dlaczego signal_handler wciąż wywołuje: Po powrocie z obsługi sygnału, FPE ponownie wykonać tę samą instrukcję. Możesz tego uniknąć, używając longjmp.

Oto mój kod działa dobrze dla celów (przynajmniej na Mac OS X) https://github.com/nishio/learn_language/blob/master/zero_division/zero_division.cpp

+0

Wydaje się również działać na 'g ++' i 'clang ++' na 'ubuntu' – ubershmekel