2009-10-06 7 views
6

Je suis en cours d'exécution dans un problème avec des exceptions en virgule flottante est activée dans Visual Studio 2005. Si je code comme ceci:pile à virgule flottante manutention avec des exceptions en virgule flottante sous tension

double d = 0.0; 
    double d2 = 3.0; 
    double d3 = d2/d; 

et si je me inscrire une routine de gestionnaire SEH, alors je peux facilement transformer le div-by-zero en une exception C++ et l'attraper. Jusqu'ici tout va bien.

Cependant, lorsque je fais cela, le premier opérande (0.0 dans l'exemple ci-dessus) est laissé sur la pile de registres FPU. Si je le fais huit fois, alors je commencerai à obtenir une exception de vérification de pile à virgule flottante avec TOUTES les opérations à virgule flottante à partir de maintenant.

Je peux m'occuper de ceci en utilisant un bloc __asm ​​pour exécuter un FSTP, faisant ainsi sortir la valeur parasite de la pile, et tout va bien.

Cependant, cela m'inquiète, parce que je n'ai pas vu cela discuté partout. Comment puis-je être certain du nombre de valeurs que je devrais afficher? Est-il sûr de simplement faire apparaître tout ce qui est sur la pile au moment de l'exception? Existe-t-il des meilleures pratiques recommandées dans ce domaine?

Merci!

+0

Est-ce que ça arrive aussi avec SEH? Si vous ne vous inscrivez pas, le gestionnaire SEH se comporte-t-il de la même manière? –

+0

Cela arrive à la suite de l'appel _controlfp() qui démasque les exceptions qui m'intéressent (comme div-by-zero). Je ne pense pas que cela soit important si j'ai un gestionnaire SEH enregistré ou non - mais si je ne le fais pas, je tombe en panne avec une exception non gérée. –

Répondre

3

Bien que je ne trouve rien non plus, je peux donner quelques explications quant à la réponse probable:

L'ABI définit que sur une fonction appeler la pile doit être vide, et il devrait être à nouveau vide à la sortie sauf si le retour est une valeur à virgule flottante, où il serait le seul élément de la pile.

Étant donné que le gestionnaire d'exceptions doit pouvoir retourner à n'importe quel endroit, certains critères doivent être conservés sur ces emplacements. La question ici est, est-ce que le dérouleur de pile a une connaissance quelconque de la pile FPU de la fonction ayant le catch()? Très probablement, la réponse est non car il est plus facile et plus rapide de créer un point de retour approprié avec des propriétés fixes que d'inclure la pile FPU complète dans le déroulement. Ce qui conduit à votre problème - normalement lever une exception a le compilateur prendre soin de la FPU étant vide, mais dans un gestionnaire SEH, le compilateur n'a aucune idée qu'il a causé une entrée dans une autre fonction, et ne peut donc pas prendre soin des choses au cas où. (autre que ce qui est encore hideusement lent)

Ce qui signifie que très probablement, la pile FPU devrait être dans son état "cohérent" à son retour, ce qui signifie que vous voulez probablement un équivalent d'une instruction EMMS.

Pourquoi EMMS? Eh bien, à moins qu'il ne soit pas pris en charge, il effectue les opérations suivantes:

  • clairement la pile (qui fixe tous les arguments à virgule flottante restes)
  • efface les balises de la pile (qui fixe une pile inutilisable lors de la sortie d'un MMX activé fonction)

Si vous voulez supporter le Pentium 1 ou pire, vous pouvez évidemment utiliser() autour de l'EMMS et utiliser autre chose à la place.

Aucune garantie bien sûr, mais j'espère que j'ai expliqué le pourquoi de la réponse probable suffisamment.

+0

Cela a du sens - j'étais arrivé à peu près à la même conclusion. Merci. –

Questions connexes