C++ : Rattraper une erreur de division par zéro
Ici est un simple morceau de code où une division par zéro se produit. Je suis en train d'essayer de l'attraper :
#include <iostream>
int main(int argc, char *argv[]) {
int Dividend = 10;
int Divisor = 0;
try {
std::cout << Dividend / Divisor;
} catch(...) {
std::cout << "Error.";
}
return 0;
}
Mais l'application se bloque de toute façon (même si j'ai mis l'option -fexceptions
de MinGW).
Est-il possible de prendre une telle exception (que je comprends, c'est pas une des exceptions C++, mais un FPU exception) ?
Je suis conscient que je pourrais consulter pour le diviseur avant la division, mais j'ai fait l'hypothèse que, parce qu'une division par zéro est rare (au moins dans mon application), il serait plus efficace d'essayer de la division (et la capture de l'erreur si elle se produit) que de tester à chaque fois le diviseur avant de se diviser.
Je suis en train de faire ces tests sur un WindowsXP ordinateur, mais vous souhaiteriez en faire de la croix-plate-forme.
if (Divisor == 0) { std::cout << "Error."; exit; }
. Vous ensuite d'éliminer toute cause de ce qui se passe. Ensuite, vous pouvez supprimer le conditionnel et l'expédition de votre produit avec pas de division par des zéros.- (Un
assert(Divisor != 0)
serait plus canonique. N'oubliez pas de développer en cours d'exécution à travers un débogueur!) - Ce n'est même pas un FPU exception, mais le CPU exception. FPU poignées de nombres à virgule flottante, mais vous obtiendrez NaN ou l'infini, avec elle, pas un plantage.
- Règle de base: TOUJOURS (et dans le cas où vous avez manqué l'accent: TOUJOURS!) vérifiez vos informations avant de faire les calculs et vous éviter ces types de problèmes.
- "J'ai fait l'hypothèse que, parce qu'une division par zéro est rare (au moins dans mon application), il serait plus efficace" - alors il ne faut pas faire de telles hypothèses avant d'exécuter le générateur de profils. Faire des hypothèses sur le bleu est une façon d'échouer lors de l'optimisation. Faites confiance à votre optimiseur et votre CPU de la direction de la prévision.
- Java n'a pas de problème: ideone.com/Ro5mw3. C'est probablement les tests à chaque diviseur avant de passer à la CPU.
Vous devez vous connecter pour publier un commentaire.
Ce n'est pas une exception. C'est un erreur qui est déterminé à matériel niveau et est retournée au système d'exploitation, qui en informe ensuite votre programme dans certains OS de manière spécifique à ce sujet (comme, par tuer le processus).
Je croire que, dans de tels cas, ce qui se passe n'est pas une exception, mais un signal. Si c'est le cas: Le système d'exploitation interrompt votre principal du programme de contrôle de débit et les appels d'un gestionnaire de signal, qui - à son tour - arrête le fonctionnement de votre programme.
C'est le même type d'erreur qui s'affiche lorsque vous déréférencement d'un pointeur null (puis votre programme se bloque par signal SIGSEGV, segmentation fault).
Vous pouvez essayer d'utiliser les fonctions de
<csignal>
- tête pour essayer de donner un gestionnaire personnalisé pour le signal SIGFPE (c'est pour virgule flottante exceptions, mais c'est peut être le cas, elle est également soulevée pour la division entière par zéro - je suis vraiment pas sûr ici). Vous devez cependant noter que le traitement du signal est OS-dépendante et MinGW en quelque sorte "émule" les signaux POSIX sous l'environnement Windows.Voici le test sur MinGW 4.5, Windows 7:
De sortie:
Et à droite après l'exécution du gestionnaire de signal, le système tue le processus et affiche un message d'erreur.
En utilisant cela, vous pouvez fermer toutes les ressources de journal ou un message d'erreur après une division par zéro ou un déréférencement de pointeur null... mais contrairement aux exceptions qui n'est PAS un moyen pour contrôler votre programme de flux, même dans des cas exceptionnels. Un programme ne devrait pas le faire. La capture de ces signaux n'est utile pour le débogage/diagnostic fins.
(Il y a certains signaux qui sont très utiles en général dans la programmation de bas niveau et ne causent pas de votre programme pour être tué tout de suite après le gestionnaire, mais c'est un profond sujet).
La division par zéro est une erreur de logique, un bug par le programmeur. Vous ne devriez pas essayer d'y faire face, vous devez déboguer et de l'éliminer. En outre, la capture des exceptions est extrêmement coûteux - de façon plus que diviseur vérification sera.
Vous pouvez utiliser la gestion Structurée des exceptions pour rattraper l'erreur de division par zéro. Comment c'est réalisé dépend de votre compilateur. MSVC propose une fonction pour récupérer Structurée des Exceptions comme
catch(...)
et fournit également une fonction de traduire Structurée des Exceptions dans les exceptions, ainsi que l'offre__try
/__except
/__finally
. Cependant, je ne suis pas assez familier avec MinGW pour vous dire comment le faire dans ce compilateur./
opérateur est très lourd. Puis, quelque chose comme Windows SEH est un bon secours.Il n'y a n'est pas un
la langue standard manière de capter l'
la division par zéro de la CPU.
Ne pas prématurément "optimiser" l'écart d'un
de la branche. Votre demande est
vraiment le CPU dans ce contexte? J'en doute, et il n'est pas vraiment un
optimisation si vous cassez votre code.
Sinon, je pourrais faire de votre code
encore plus rapide:
Division par zéro n'est pas une exception en C++, voir https://web.archive.org/web/20121227152410/http://www.jdl.co.uk/briefings/divByZeroInCpp.html
En quelque sorte la véritable explication est toujours manquant.
Oui, votre
catch
bloc devrait fonctionner sur certains compilateurs. Mais le problème est que vos exception n'est pas de FPU exception. Vous faites division entière. Je ne sais pas si c'est aussi un catchable d'erreur, mais il n'est pas de FPU exception, qui utilise une fonctionnalité de l'IEEE sur la représentation des nombres en virgule flottante.catch(...)
dans la norme C++. Mais au moins un compilateur a soutenu, il y a longtemps. À savoir, Visual C++ une fois avait que comme une extension du langage. Je crois, me souviens, que l'extension était présent dans la version 6.0, qui a été pré-norme, et a été abandonné dans la version 7.0, le premier Visuel Studio.NET version et post C++98.Sur Windows (Visual C++), essayez ceci:
MSDN: http://msdn.microsoft.com/en-us/library/ms681409(v=vs. 85).aspx
Bien, si il y a une exception de manutention à ce sujet, quelques élément nécessaires pour faire le vérifier. Par conséquent, vous ne perdez rien si vous le vérifier vous-même. Et il n'y a pas beaucoup qui est plus rapide qu'une simple comparaison de résultats (une seule CPU "d'instruction saut si égal à zéro" ou quelque chose comme ça, ne me souviens pas le nom)
Pour éviter infini "Signal 8 ici!" les messages, il suffit d'ajouter "quitter" pour Kos nice code:
Comme les autres ont dit, ce n'est pas une exception, il génère simplement un NaN ou Inf.
Zéro fracture n'est qu'un moyen de le faire. Si vous faites beaucoup de maths, il y a beaucoup de façons, comme
log(not_positive_number)
,exp(big_number)
, etc.Si vous pouvez vérifier la validité des arguments avant de faire le calcul, puis le faire, mais parfois, c'est dur à faire, alors vous pouvez avoir besoin de générer et de gérer une exception.
Dans MSVC il y a un fichier d'en-tête
#include <float.h>
contenant une fonction_finite(x)
qui indique si un nombre est fini.Je suis sûr que MinGW a quelque chose de similaire.
Vous pouvez tester que, après un calcul et lancer/attraper votre propre exception ou quoi que ce soit.