La norme ANSI mandat à court-circuiter les opérateurs logiques, en C ou C ++?
Je suis confus car je me souviens du livre K&R disant que votre code ne devrait pas dépendre du court-circuit de ces opérations, car elles peuvent ne pas l'être. Quelqu'un pourrait-il indiquer où dans la norme il est dit que les opérations logiques sont toujours court-circuitées? Je suis surtout intéressé par C ++, une réponse également pour C serait géniale.
Je me souviens aussi avoir lu (je ne me souviens pas où) que l'ordre d'évaluation n'est pas strictement défini, donc votre code ne devrait pas dépendre ou assumer que les fonctions d'une expression seraient exécutées dans un ordre spécifique: à la fin d'une instruction, toutes les fonctions référencées aura été appelé, mais le compilateur a la liberté de sélectionner l'ordre le plus efficace.
La norme indique-t-elle l'ordre d'évaluation de cette expression?
if( functionA() && functionB() && functionC() ) cout<<"Hello world";
Réponses:
Oui, un court-circuit et un ordre d'évaluation sont requis pour les opérateurs
||
et&&
dans les normes C et C ++.La norme C ++ dit (il devrait y avoir une clause équivalente dans la norme C):
En C ++, il y a un piège supplémentaire: le court-circuit ne s'applique PAS aux types qui surchargent les opérateurs
||
et&&
.Il n'est généralement pas recommandé de surcharger ces opérateurs en C ++, sauf si vous avez une exigence très spécifique. Vous pouvez le faire, mais cela peut interrompre le comportement attendu dans le code d'autres personnes, en particulier si ces opérateurs sont utilisés indirectement via des modèles d'instanciation avec le type surchargeant ces opérateurs.
la source
L'évaluation des courts-circuits et l'ordre d'évaluation sont une norme sémantique obligatoire en C et C ++.
Si ce n'était pas le cas, un code comme celui-ci ne serait pas un idiome courant
La section 6.5.13 Opérateur ET logique de la spécification C99 (lien PDF) dit
De même, la section 6.5.14 Opérateur logique OR dit
Des termes similaires peuvent être trouvés dans les normes C ++, consultez la section 5.14 de ce projet de copie . Comme les vérificateurs le notent dans une autre réponse, si vous remplacez && ou ||, les deux opérandes doivent être évalués car ils deviennent un appel de fonction normal.
la source
Oui, cela l'exige (ordre d'évaluation et court-circuit). Dans votre exemple, si toutes les fonctions retournent true, l'ordre des appels est strictement à partir de functionA puis functionB puis functionC. Utilisé pour cela comme
Idem pour l'opérateur virgule:
On dit entre la gauche et la droite opérande
&&
,||
,,
et entre le premier et le deuxième / troisième opérande?:
(opérateur conditionnel) est un « point de séquence ». Tous les effets secondaires sont évalués complètement avant ce point. Donc, c'est sûr:Notez que l'opérateur virgule ne doit pas être confondu avec la virgule syntaxique utilisée pour séparer les choses:
La norme C ++ dit dans
5.14/1
:Et dans
5.15/1
:Il dit pour les deux à côté de ceux-ci:
En plus de cela,
1.9/18
ditla source
Tout droit sorti du bon vieux K&R:
la source
Soyez très très prudent.
Pour les types fondamentaux, il s'agit d'opérateurs de raccourcis.
Mais si vous définissez ces opérateurs pour vos propres types de classe ou d'énumération, ils ne sont pas des raccourcis. En raison de cette différence sémantique dans leur utilisation dans ces différentes circonstances, il est recommandé de ne pas définir ces opérateurs.
Pour les types fondamentaux
operator &&
etoperator ||
pour les types fondamentaux, l'ordre d'évaluation est de gauche à droite (sinon un raccourci serait difficile :-) Mais pour les opérateurs surchargés que vous définissez, il s'agit essentiellement de sucre syntaxique pour définir une méthode et donc l'ordre d'évaluation des paramètres est indéfini.la source
Votre question se résume à la priorité des opérateurs C ++ et à l'associativité. Fondamentalement, dans les expressions avec plusieurs opérateurs et sans parenthèses, le compilateur construit l'arborescence des expressions en suivant ces règles.
Pour la priorité, lorsque vous avez quelque chose comme
A op1 B op2 C
, vous pouvez regrouper les éléments sous la forme soit(A op1 B) op2 C
ouA op1 (B op2 C)
. Siop1
a une priorité plus élevée queop2
, vous obtiendrez la première expression. Sinon, vous obtiendrez le deuxième.Pour l'associativité, lorsque vous avez quelque chose comme
A op B op C
, vous pouvez à nouveau regrouper les minces comme(A op B) op C
ouA op (B op C)
. Siop
a quitté l'associativité, on se retrouve avec la première expression. S'il a la bonne associativité, on se retrouve avec la seconde. Cela fonctionne également pour les opérateurs au même niveau de priorité.Dans ce cas particulier,
&&
a une priorité plus élevée que||
, donc l'expression sera évaluée comme(a != "" && it == seqMap.end()) || isEven
.L'ordre lui-même est "de gauche à droite" sur la forme d'arbre d'expression. Nous allons donc d'abord évaluer
a != "" && it == seqMap.end()
. Si c'est vrai, toute l'expression est vraie, sinon on passe àisEven
. La procédure se répète de manière récursive dans la sous-expression de gauche bien sûr.Quelques informations intéressantes, mais le concept de priorité a ses racines dans la notation mathématique. La même chose se produit dans
a*b + c
, où*
a une priorité plus élevée que+
.Encore plus intéressant / obscur, pour une expression sans parenté
A1 op1 A2 op2 ... opn-1 An
, où tous les opérateurs ont la même priorité, le nombre d'arbres d'expressions binaires que nous pourrions former est donné par les nombres dits catalans . Pour les grandsn
, ceux-ci se développent extrêmement rapidement. réla source
Si vous faites confiance à Wikipédia:
C (langage de programmation)
la source