Lorsque vous écrivez ceci:
line 4: warning C4723: potential divide by 0
8 Réponses :
Le compilateur n'est pas en mesure d'analyser statiquement tous les chemins de code et de prendre en compte toutes les possibilités tout le temps. Théoriquement, une analyse complète d'un comportement de programme Juste en examinant son code source peut fournir une solution à la halte de problème, ce qui est indécitable. Les compilateurs ont un ensemble limité de règles d'analyse statique pour détecter les règles. La norme C ++ ne nécessite pas que le compilateur émet un tel type d'avertissements. Ce n'est pas un bug. C'est plus comme une fonctionnalité inexistante. P>
Tu as raison. Il ne peut jamais être un bug du point de vue standard C ++, car cela concerne les avertissements. Cependant, si ce «défaut» me force à réécrire le code parfaitement valide (ou à l'entourer avec #pragma code> s), à partir d'un point de vue de «programme informatique», c'est un bug.
@xtofl: le mot clé dans l'avertissement est "potentiel"
D'accord, mais la douleur essentielle est que nous essayons de traiter des avertissements comme des erreurs et ne peuvent pas le faire avec des avertissements «faux positifs».
@xtofl: Vous utilisez un outil. Si cela donne des avertissements inutiles, vous devrez les ignorer. C'est peut-être un "bogue" pour vous, mais c'est l'outil que vous utilisez et vous ne pouvez pas la modifier.
@xtofl: Vous pourriez avoir l'avertissement #pragma (désactiver: 4723)
Non, l'opérateur conditionnel n'évalue pas les deux arguments. Cependant, une division potentielle à zéro, si un compilateur peut détecter une telle chose, est généralement rapporté. Il n'est pas inauguré que la norme prend environ 2 pages pour décrire le comportement de cet opérateur. P>
de N-4411: P>
5.16 opérateur conditionnel strong> p> 1 strong> groupe d'expressions conditionnel de droite à gauche. La première expression est convertis contextuellement en bool (clause 4). Il est évalué et s'il est vrai, le résultat du conditionnel L'expression est la valeur de la seconde expression, sinon celle de la troisième expression. Seulement un des deuxième et troisième expressions est évalué. Chaque calcul de la valeur et Effet secondaire associé au premier l'expression est séquencée avant chaque Calcul de la valeur et effet secondaire associé au deuxième ou troisième expression. p> blockQuote>
Aussi, note: p>
3 strong> sinon, si les deuxième et troisième opérande a différents types, et soit a (éventuellement qualifié de CV) type de classe, une tentative est faite à convertir chacun de ces opérandes vers le Type de l'autre. P> blockQuote> L'exemple que vous avez cité a le même type pour les deuxième et troisième expressions - Soyez assuré, seul le premier sera évalué. P>
Je doute que le point 3 dit réellement que les deux opérandes seront évaluées. Je pense que cela concerne plutôt si des choses comme std :: string s ("a"); const char * c = "b"; std :: string a = cond ()? S: c; const char * b = cond ()? S: c; code> doit compiler ou non (déterminer le type de résultat de l'opérateur: le compilateur vérifie ce qui peut être jeté à quoi - dans ce cas le premier?: compile, puisque
const Char * code> peut être implicitement converti en STD :: String, mais la seconde ne compile pas, car le type de résultat de l'opérateur est
std :: string code>, et cela ne peut pas être converti implicitement à
const char * code>)
Le code de la division sera généré, d'où l'avertissement. Mais la branche ne sera jamais prise lorsque arg code> est égal à 0, de sorte qu'il est sûr. p>
opérateur == pour les numéros de points flottants est dangereux (c'est-à-dire que vous ne pouvez pas y faire confiance, en raison de problèmes d'arrondi). Dans ce cas particulier, il est en fait sûr, vous pouvez donc ignorer l'avertissement, mais le compilateur ne fera pas une telle analyse basée sur un opérateur dont les résultats sont quelque peu imprévisibles dans l'affaire Général. P>
L'opérateur conditionnel ne doit pas évaluer tous les arguments. Mais je crois que vous pouvez prendre Au fait, Visual C ++ 2008 ne donne pas un tel avertissement. P> arg code> presque égale à 0, donc
arg == 0.0 code> sera
faux code>, mais
1./arg code> donnera "division par zéro" résultat. Donc, je pense que cet avertissement est utile ici. P>
IEEE 754 Les divisions de points flottants en C ne lanceront pas de diviser par zéro. Le résultat de la division par zéro sera + infini, -infinity ou nan
Le résultat peut être + infini ou -infinity pour des nombres sous-formels, mais j'appellerais qu'un débordement plutôt qu'une division par zéro.
@starBlue: presque correct. 1./arg code> ne peut pas trop déborder.
10.0 / arg code> pourrait déborder, cependant. (à nouveau en supposant que IEEEE754, 1e0 / 2e-308 = 5E307, qui est <1.7E308)
En plus des autres commentaires: L'avertissement génère par le compilateur, la branche morte est supprimée par l'optimiseur qui fonctionne plus tard - éventuellement même à la phase de liaison. P>
Donc non, ce n'est pas un bug. L'avertissement est un service supplémentaire fourni par le compilateur, non obligatoire par la norme. C'est un effet secondaire malheureux de l'architecture compilation / liante. p>
C'est un bug évident, au-delà du doute. P>
L'intention de l'avertissement n'est pas de prévenir toutes les divisions d'un programme. Ce serait beaucoup trop bruyant dans un programme raisonnable. Au lieu de cela, l'intention est de vous avertir lorsque vous devez vérifier un argument. Dans ce cas, vous avez vérifié l'argument. Par conséquent, le compilateur aurait dû noter que et tais-toi. P>
La mise en oeuvre technique d'une telle fonctionnalité est effectuée par des variables d'étiquetage dans les branches de code avec certains attributs. L'un des attributs les plus courants est le tri-État "est null". Avant la branche, Maintenant, lorsqu'il s'agit de générer des avertissements de pointeur divisée et nul, le Mais comment savons-nous que le compilateur utilise un tel arg code> est une variable externe et
arg [[isnull]] code> est inconnu. Mais après la vérification sur
arg code> il y a deux branches. Dans la première branche
arg [[isnull]] code> est vrai. Dans la deuxième branche
arg [[isnull]] code> est faux. P>
[[ISNULL] code> attribut doit être vérifié. Si true, vous avez un avertissement / une erreur sévère. Si inconnu, vous devez générer l'avertissement ci-dessus - un problème potentiel, au-delà de ce que le compilateur peut prouver. Mais dans ce cas, l'attribut
[[isnull]] code> est faux. Le compilateur de la même logique formelle que les humains, sait qu'il n'y a pas de risque. P>
[[ISNULL]] code> attribuer en interne? Rappelez-vous le premier paragraphe: sans cela, il faudrait soit avertir toujours ou jamais. Nous savons qu'il avertit parfois, ergo il doit y avoir un
[[isnull]]] code> attribut. P>
C'est un raisonnement solide. Je peux vivre avec ça - précisément puisqu'il prouve mon sentiment de gut.
Un bogue Linux récent a été causé par exactement cet attribut. Dans le code fautif, un pointeur était d'abord alérés (fondamentalement int * Membre = & (Barre FOO->); code> et ensuite vérifié
si (! Foo) retourner; code>. Toutefois. , en raison de la déséroférence, le
FOO [[ISNULL]] code> est déjà défini sur FALSE, et le chèque null optimisé.
Vous pourriez être capable d'éviter l'avertissement en utilisant le mot-clé peut valoir un coup. Ou bien sûr, il suffit de faire taire l'avertissement pendant cette fonction, avec le __ d'assumer CODE> Microsoft. Je ne sais pas si vous pouvez l'attacher avec l'opérateur conditionnel. Sinon, quelque chose comme
#pragma approprié code>. P> p>
Prenez soin de la comparaison des "doubles" arguments sur l'égalité. Mauvais magie arrive là-bas ...
Non ça ne le fait pas. Processus parfaitement bien défini. En particulier,
0,0 == -0.0 code>. Par conséquent, pour tous les ensembles de valeurs pour lesquels
1./arg code> est défini, nous savons que
arg! = 0.0 code>.
@Msalters: Mais en raison des erreurs d'arrondi, arg, peut ne pas être 0,0 (ou -0,0.0.0.0.0.0.0.0 à cette affaire) lorsque vous vous attendiez.
Ce n'est pas un bug en ce qui concerne la conformité des normes. Mais cela ne signifie pas que vous ne pouvez pas soumettre un rapport de bogue à Connect.Microsoft.com. Vous avez raison que dans ce cas, il pourrait être raisonnable de s'attendre à ce que le compilateur détermine que la division par zéro ne peut jamais arriver. Laissez Microsoft savoir alors.
@jalf: True, il peut ne pas être zéro à cause de l'arrondi. Mais dans ce cas, il n'y a pas de fracture par zéro. Les deux états suivants sont entièrement équivalents et interchangeables:
x == 0 code> et
1./x est une division par zéro code> (sous IEE754 et toutes les autres implémentations que je connaisse)