174 votes

La mise en court-circuit des opérateurs booléens est-elle obligatoire en C / C ++? Et ordre d'évaluation?

La norme ANSI mandat opérateurs de logique pour être en court-circuit, soit en C ou C++?

Je suis confus car je rappel que le K&R livre en disant: votre code ne doit pas dépendre de ces opérations étant court-circuité, car ils ne peuvent pas. Quelqu'un pourrait s'il vous plaît signaler où, dans la norme, il est dit que la logique des opérations sont toujours en court-circuit? Je suis surtout intéressé sur le C++, une réponse aussi pour C serait génial.

Je me souviens aussi de la lecture (ne me souviens pas où) que l'ordre d'évaluation n'est pas strictement définie, de sorte que votre code ne doit pas dépendre ou d'assumer des fonctions au sein d'une expression à être exécutés dans un ordre spécifique: à la fin d'un énoncé de toutes référencées fonctions auront été appelé, mais le compilateur a la liberté de choisir la voie la plus efficace.

La norme indiquent l'ordre d'évaluation de cette expression?

if( functionA() && functionB() && functionC() ) cout<<"Hello world";

187voto

Alex B Points 34304

Oui, de court-circuit et l'ordre d'évaluation sont nécessaires pour les opérateurs || et && en C et C++ normes.

C++ standard dit (il devrait y avoir un article équivalent dans la norme C):

1.9.18

Dans l'évaluation des expressions suivantes

a && b
a || b
a ? b : c
a , b

en utilisant le haut-sens des opérateurs dans ces expressions, il y a un point de séquence après l'évaluation de la première expression (12).

En C++ il y a un piège supplémentaire: court-circuit ne PAS s'appliquer à des types de surcharge des opérateurs || et &&.

Note de bas de page 12: Les opérateurs indiqués dans ce paragraphe sont intégrés dans les opérateurs, comme décrit dans la clause 5. Lorsque l'un de ces opérateurs est en surcharge (clause 13) dans un contexte valide, donc la désignation d'un opérateur défini par l'utilisateur de la fonction, l'expression désigne une invocation de la fonction, et les opérandes forme d'une liste d'arguments, sans implicite de point de séquence entre eux.

Il est généralement recommandé de ne pas surcharger ces opérateurs en C++, sauf si vous avez une exigence particulière. Vous pouvez le faire, mais il peut briser comportement attendu dans d'autres gens du code, surtout si ces opérateurs sont utilisés indirectement par l'intermédiaire de l'instanciation de modèles avec le type de la surcharge de ces opérateurs.

79voto

Paul Dixon Points 122033

Court-circuit de l'évaluation et de l'ordre de l'évaluation, est un mandat sémantique standard en C et C++.

Si ce n'était pas le cas, le code que ce ne serait pas un idiome commun

   char* pChar = 0;
   // some actions which may or may not set pChar to something
   if ((pChar != 0) && (*pChar != '\0')) {
      // do something useful

   }

Section 6.5.13 Logique ET de l'exploitant de la C99 spécification (lien PDF) dit

(4). Contrairement à la bit-à-bit binaire opérateur&, & & garanties opérateur de gauche à droite de l'évaluation; il est un point de séquence après l'évaluation de le premier opérande. Si le premier opérande compare égal à 0, le deuxième opérande n'est pas évalué.

De même, l'article 6.5.14 opérateur Logique OU dit

(4) Contrairement à l'opérateur|, le || opérateur garantit de gauche à droite d'évaluation; il est un point de séquence après l'évaluation de la première l'opérande. Si le premier opérande compare inégales à 0, le deuxième opérande est pas évaluée.

Libellé similaire peut être trouvée dans les normes C++, consultez la section 5.14 dans ce projet exemplaire. Comme les pions de notes dans une autre réponse, si vous substituez && ou ||, puis les deux opérandes doivent être évalués comme il devient un appel de fonction.

19voto

Oui, c'mandats (à la fois l'ordre d'évaluation et de court-circuit). Dans votre exemple, si toutes les fonctions renvoient vrai, l'ordre des appels sont strictement de functionA puis functionB et puis functionC. Utilisé comme

if(ptr && ptr->value) { 
    ...
}

De même pour l'opérateur virgule:

// calls a, then b and evaluates to the value returned by b
// which is used to initialize c
int c = (a(), b());

On dit entre la gauche et la droite opérande &&, ||, , et entre la première et la deuxième/troisième opérande ?: (opérateur conditionnel) est un "point de séquence". Les effets secondaires sont évalués complètement avant ce point. Donc, c'est sûr:

int a = 0;
int b = (a++, a); // b initialized with 1, and a is 1

Notez que l'opérateur virgule n'est pas à confondre avec la syntaxe utilisé par des virgules pour séparer les choses:

// order of calls to a and b is unspecified!
function(a(), b());

La Norme C++, dit en 5.14/1:

Le && opérateur de groupes de gauche à droite. Les opérandes sont à la fois implicitement converti vers le type bool (clause 4). Le résultat est true si les deux opérandes sont true et false sinon. Contrairement &, && garanties de gauche à droite évaluation: le deuxième opérande n'est pas évalué si le premier opérande est faux.

Et dans 5.15/1:

L'opérateur || groupes de gauche à droite. Les opérandes sont à la fois implicitement converti en booléen (clause 4). Elle retourne true si l'une des opérandes est vrai, et faux sinon. À la différence de |, || les garanties de gauche à droite de l'évaluation; de plus, le deuxième opérande n'est pas évalué si le premier opérande est évaluée à true.

Il est dit pour les deux à côté de ceux-ci:

Le résultat est un booléen. Tous les effets secondaires de la première expression, sauf pour la destruction des temporaires (12.2) arrivera pas avant la deuxième expression est évaluée.

En outre, 1.9/18 dit

Dans l'évaluation de chacune des expressions

  • a && b
  • a || b
  • a ? b : C
  • a , b

en utilisant le haut-sens des opérateurs dans ces expressions (5.14, 5.15, 5.16, 5.18), il y a un point de séquence après l'évaluation de la première expression.

9voto

John T Points 14067

Tout droit du bon vieux K & R:

C garantit que &&' and || ' sont évalués de gauche à droite - nous verrons bientôt des cas où cela compte.

5voto

Loki Astari Points 116129

Être très, très prudent.

Pour POD ces types sont de raccourci opérateurs.

Mais si vous définissez ces opérateurs pour vos propres classes, ils ne sont pas de raccourci. En raison de cette différence sémantique dans leur utilisation dans ces différentes circonstances, il est recommandé que vous ne définissez pas de ces opérateurs.

Pour les opérateurs && et | opérateur| POD types de l'ordre d'évaluation est de gauche à droite (sinon une coupe courte serait dur :-) Mais pour les opérateurs surchargés que vous définissez, ce sont essentiellement sucre syntaxique pour la définition d'une méthode et donc l'ordre d'évaluation des paramètres n'est pas défini.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X