2009-07-21 6 views
0

Pour une raison quelconque, quand je reviens du gestionnaire de signal pour SIGFPE, la variable i est un de moins que ce que j'attends, pour obtenir les bons résultats de mon programme (parcourir tous les les paires dans le tableau de paires) Je dois vérifier la valeur de retour de sigsetjmp et incrémenter i si je reviens d'un signal "catch". Pourquoi est-ce? Pourquoi l'incrémentation qui se produit lors de l'itération de l'exception à virgule flottante est-elle perdue?problème obscur avec sigsetjmp sur linux avec C

#include <stdio.h> 
#include <signal.h> 
#include <stdlib.h> 
#include <setjmp.h>                

jmp_buf e; 

int i; 
void float_exception(); 
int main() 
{ 
    int pairs[][2] = { 
     {10, -5}, {10, -3}, {-10, -3}, {-10, -5}, {-10, 3}, {-10, 5}, {-10, 0}, 
     {10, 0}, {0, 10}, {2, 3}, {3, 3}, {5, 10} 
    }; 
    int npairs; 
    /* handle sigfpe so /0 doesn't interrupt the rest of the program */ 
    signal (SIGFPE, float_exception); 
    printf ("Seeing what my C implementation does with negative or 0 modulo" 
      "\narithmetic.\n"); 
    npairs = sizeof (pairs)/sizeof (int)/2; 
    i = 0; 

    if (sigsetjmp (e, 1) != 0) { 
     i++; /* without this line, i is one less than I expect it to be */ 
    } 
    for (; i < npairs - 1; i++) { 
     printf ("%d: %d %% %d\t= ", i, pairs[i][0], pairs[i][1]); 
     fflush (stdout); 
     printf ("%d\n", pairs[i][0] %pairs[i][1]); 
     fflush (stdout); 
    } 
    return 0; 
} 



void float_exception() 
{ 
    printf ("fpe\n"); 
    fflush (stdout); 
    longjmp (e, 1); 
} 

Répondre

0

La réponse de caf semble être juste.

Ce que je m'attendais initialement, c'est que j'ai besoin d'être déclaré volatile. Au moins c'est ce que l'auteur de NSBlog claims.

Une autre chose à noter: il peut être dangerous pour appeler printf et fflush à l'intérieur d'un gestionnaire de signal. Étant donné que SIGFPE est un signal synchrone, ce n'est pas totalement hors de question, mais vous devriez savoir ce que vous faites. Enfin, à partir de la page de manuel Linux: "longjmp() et siglongjmp() rendent les programmes difficiles à comprendre et à maintenir, si possible, une alternative devrait être utilisée."

+0

J'avais essayé de déclarer i volatile en vain, je pense la réponse de café est bon aussi. long/sigset/JMP était la seule chose que je pouvais constater que me laisserait sauter hors de la fonction de rappel et revenir à la boucle, sinon l'exception continue à émettre le signal encore et encore (c'est la division par zéro, donc je ne suis pas vraiment surpris), et pour sortir de cette boucle, je J'ai besoin de sauter du gestionnaire de signal dans un autre bloc de code.Je suppose que je peux utiliser un mutex autour de la stdio dans float_execption() –

+0

Appeler * any * fonction de bibliothèque sauf signal() à partir d'un gestionnaire de signal est dangereux. J'ai été mordu par cela personnellement, nous avons appelé printf() depuis un gestionnaire de signal, mais au lieu d'écrire le message sur la console, il a écrasé la partie o f un fichier Access .mdb que nous étions en train de mettre à jour, arrosant la base de données de manière irréparable. Franchement, C ne fournit pas de très bons outils pour gérer des exceptions comme celle-ci; vous feriez bien mieux de vérifier vos arguments avant de tenter l'opération. –

+0

@Ringding, wellDdivision par zéro est un comportement indéfini, donc Tom n'a aucune garantie (donnée par la norme C. La norme POSIX peut donner des garanties, je ne sais pas) qu'un signal arrive. Une autre chose est que, bien sûr, la valeur de i n'est pas garantie d'être stockée à travers le saut du tout. La valeur de i est non spécifiée. C'est pourquoi volatile est nécessaire. Son programme repose à la fois sur un comportement indéfini et sur des valeurs non spécifiées. Mais à la fin de la journée, le programme se déroule dans une mise en œuvre, pas sur le PDF standard, donc si le gars sait ce qu'il fait, il va bien. –

3

Cela me semble juste. Le "normal" i ++ se produit à la fin de la boucle for() - et si vous appelez longjmp (e, 1), vous ignorez cela.

+0

Je ne comprenais pas ce jusqu'à maintenant :(doh. –