web-dev-qa-db-fra.com

La division non évaluée par 0 comportement n'est-elle pas définie?

Je suis en désaccord avec certains collègues sur le code suivant:

int foo ( int a, int b )
{
    return b > 0 ? a / b : a;
}

Ce code présente-t-il un comportement indéfini?

EDIT: le désaccord a commencé à partir de ce qui semble être un bogue dans un compilateur d'optimisation trop désireux, où le b > 0 la vérification a été optimisée.

61
Luchian Grigore

Non.


Citations de N4140:

§5.16 [expr.cond]/1

Groupe d'expressions conditionnelles de droite à gauche. La première expression est convertie contextuellement en bool. Il est évalué et s'il est vrai, le résultat de l'expression conditionnelle est la valeur de la deuxième expression, sinon celle de la troisième expression. ne seule desles deuxième et troisième expressions sont évaluées.

Plus loin:

§5 [expr]/4

Si, lors de l'évaluation d'une expression, le résultat n'est pas défini mathématiquement ou n'est pas dans la plage de valeurs représentables pour son type, le comportement n'est pas défini.

Cela ne se produit clairement pas ici. Le même paragraphe mentionne explicitement la division par zéro dans une note et, bien qu'il ne soit pas normatif, il rend encore plus clair que cela est pertinent dans cette situation:

[Remarque: la plupart des implémentations existantes de C++ ignorent les débordements d'entiers. Le traitement de la division par zéro, formant un reste à l'aide d'un diviseur nul, et toutes les exceptions à virgule flottante varient selon les machines et sont généralement ajustables par une fonction de bibliothèque. —Fin note]


Il existe également des preuves circonstancielles renforçant le point ci-dessus: l'opérateur conditionnel est utilisé pour rendre le comportement non défini de manière conditionnelle.

§8.5 [dcl.init] /12.3

int f(bool b) {
  unsigned char c;
  unsigned char d = c; // OK, d has an indeterminate value
  int e = d; // undefined behavior
  return b ? d : 0; // undefined behavior if b is true
}

Dans l'exemple ci-dessus, en utilisant d pour initialiser int (ou autre chose que unsigned char) n'est pas défini. Pourtant, il est clairement indiqué que l'UB ne se produit que si la branche UB est évaluée.


Sortir du point de vue du juriste: si cela pouvait être UB, alors n'importe quelle division pourrait être traitée comme UB, puisque le diviseur pourrait être 0. Ce n'est pas l'esprit de la règle.

109
krzaq

Il n'y a aucun moyen de diviser par zéro dans l'exemple de code. Lorsque le processeur exécute a / b, il a déjà vérifié que b > 0, donc b est différent de zéro.

Il convient de noter que si a == INT_MIN et b == -1, puis a/b est également un comportement indéfini. Mais cela est de toute façon empêché car la condition est évaluée à false dans ce cas.

Bien que je ne sois pas vraiment sûr que vous vouliez dire return b != 0 ? a / b : a; et pas return b > 0 ? a / b : a; Si b est inférieur à zéro, la division est toujours valide, sauf s'il s'agit de la condition décrite ci-dessus.

15
glauxosdever

Ce code présente-t-il un comportement indéfini?

Non. L'expression

return b > 0 ? a / b : a;  

est équivalent à

if(b > 0)
    return a/b;     // this will be executed only when b is greater than 0
else
    return a;  

Division effectuée uniquement lorsque b est supérieur à 0.

9
haccks

Si c'était UB, il en serait de même

if(a != null && *a == 42)
{
 .....
}

Et le séquencement des ifs, ands et ors est clairement conçu pour permettre spécifiquement ce type de construction. Je ne peux pas imaginer que vos collègues contesteraient cela

3
pm100