Comment fonctionne L'opérateur virgule

Comment fonctionne l'opérateur virgule en C++?

Par exemple, si je fais:

a = b, c;  

Est-ce que a finit par égaler b ou c?

(Oui, je sais que c'est facile à tester - il suffit de documenter ici pour que quelqu'un trouve la réponse rapidement.)

Mise à Jour: Cette question a exposé une nuance lors de l'utilisation de l'opérateur virgule. Juste pour documenter ceci:

a = b, c;    // a is set to the value of b!

a = (b, c);  // a is set to the value of c!

Cette question a été inspirée par une faute de frappe dans le code. Ce qui était censé être

a = b;
c = d;

Tourné dans

a = b,    //  <-  Note comma typo!
c = d;
154
c++
demandé sur Coding Mash 2008-09-10 18:13:39

9 réponses

, Il serait égal à b.

L'opérateur virgule a une priorité inférieure à l'affectation.

73
répondu Leon Timmermans 2017-10-13 17:04:41

Prenez soin de noter que l'opérateur virgule Peut être surchargé en C++. Le comportement réel peut donc être très différent de celui attendu.

Par exemple, Boost.Spirit utilise l'opérateur virgule assez intelligemment pour implémenter des initialiseurs de liste pour les tables de symboles. Ainsi, il rend la syntaxe suivante possible et significative:

keywords = "and", "or", "not", "xor";

Notez qu'en raison de la priorité de l'opérateur, le code est (intentionnellement!) identique à

(((keywords = "and"), "or"), "not"), "xor";

C'est-à-dire le premier opérateur appelé est {[3] } qui renvoie un objet proxy sur lequel les operator,restants sont invoqués:

keywords.operator =("and").operator ,("or").operator ,("not").operator ,("xor");
121
répondu Konrad Rudolph 2011-10-09 11:10:22

L'opérateur virgule A la priorité la plus basse de tous les opérateurs c / c++. Par conséquent, c'est toujours le dernier à se lier à une expression, ce qui signifie ceci:

a = b, c;

Est équivalent à:

(a = b), c;

Un autre fait intéressant est que l'opérateur virgule introduit un point de séquence . Cela signifie que l'expression:

a+b, c(), d

Est la garantie d'avoir trois de ses sous-expressions (a+b, c() et d) évaluées dans l'ordre. Ceci est significatif si ils ont des effets secondaires. Normalement, les compilateurs sont autorisés à évaluer les sous-expressions dans n'importe quel ordre; Par exemple, dans un appel de fonction:

someFunc(arg1, arg2, arg3)

Les Arguments peuvent être évalués dans un ordre arbitraire. Notez que les virgules dans l'appel de fonction sont des opérateurs Pas ; Ce sont des séparateurs.

115
répondu efotinis 2008-09-22 11:49:36

L'opérateur virgule:

  • a la priorité la plus basse
  • est associatif à gauche

Une version par défaut de l'opérateur virgule est définie pour tous les types (intégré et personnalisé), et il fonctionne comme suit-donné exprA , exprB:

  • {[1] } est évalué
  • le résultat de exprA est ignoré
  • {[3] } est évalué
  • le résultat de exprB est retournée comme résultat de l'ensemble de l'expression

Avec la plupart des opérateurs, le compilateur est autorisé à choisir l'ordre d'exécution et il est même nécessaire d'ignorer l'exécution si elle n'affecte pas le résultat final (par exemple {[5] } ignorera l'appel à foo). Ce n'est cependant pas le cas pour l'opérateur virgule et les étapes ci dessus se produiront toujours*.

En pratique, l'opérateur virgule par défaut fonctionne presque de la même manière qu'un point-virgule. La différence est que deux expressions séparées par un point-virgule forment deux instructions distinctes, tandis que la séparation par des virgules conserve tout comme une seule expression. C'est pourquoi l'opérateur virgule est parfois utilisé dans les scénarios suivants:

  • la syntaxe C nécessite une seule expression , pas une instruction. par exemple dans if( HERE )
  • la syntaxe C nécessite une seule instruction, pas plus, par exemple dans l'initialisation de la boucle for for ( HERE ; ; )
  • quand vous voulez sauter des accolades et garder une seule déclaration: if (foo) HERE ; (ne faites pas ça, c'est vraiment moche!)

Lorsqu'une déclaration n'est pas expression, point-virgule ne peut pas être remplacé par une virgule. Par exemple, ceux-ci sont refusés:

  • (foo, if (foo) bar) (if n'est pas une expression)
  • int x, int y (la déclaration de variable n'est pas une expression)

, Dans votre cas, nous avons:

  • a=b, c;, équivalent à a=b; c;, en supposant que a est de type qui ne surcharge pas l'opérateur virgule.
  • a = b, c = d; équivalent à a=b; c=d;, en supposant que a est de type qui ne surcharge pas la virgule opérateur.

Notez que toutes les virgules ne sont pas en fait un opérateur de virgule. Quelques virgules qui ont une signification complètement différente:

  • int a, b; - - - la liste des déclarations de variables est séparée par des virgules, Mais ce ne sont pas des opérateurs de virgule
  • int a=5, b=3; - - - c'est aussi une liste de déclarations de variables séparées par des virgules
  • foo(x,y) - - - liste d'arguments séparés par des virgules. En fait, x et y peuvent être évalués dans n'importe quel ordre!
  • FOO(x,y) --- liste d'arguments de macro séparés par des virgules
  • foo<a,b> - - - liste d'arguments de modèle séparés par des virgules
  • int foo(int a, int b) - - - liste de paramètres séparés par des virgules
  • Foo::Foo() : a(5), b(3) {} - - - liste d'initialiseurs séparés par des virgules dans un constructeur de classe

* Ce n'est pas tout à fait vrai si vous appliquez des optimisations. Si le compilateur reconnaît que certains morceaux de code n'ont absolument aucun impact sur le reste, il supprimera les instructions inutiles.

Autres lectures: http://en.wikipedia.org/wiki/Comma_operator

57
répondu CygnusX1 2013-10-05 14:49:58

La valeur de a est b, mais la valeur de l'expression sera c. C'est, dans

d = (a = b, c);

A est égal à b, et d est égal à c.

37
répondu MobyDX 2015-05-08 23:36:27

La valeur de

B sera affectée à A. Rien n'arrivera à c

8
répondu prakash 2008-09-10 14:16:54

La valeur de a sera égale à b, puisque l'opérateur virgule a une priorité inférieure à l'opérateur d'affectation.

2
répondu Jason Carreiro 2012-01-07 02:09:31

Oui L'opérateur virgule a une faible priorité que l'opérateur D'affectation

#include<stdio.h>
int main()
{
          int i;
          i = (1,2,3);
          printf("i:%d\n",i);
          return 0;
}

Sortie: i = 3
Parce que l'opérateur virgule renvoie toujours la valeur la plus à droite.
En cas d'opérateur virgule Avec opérateur D'affectation:

 int main()
{
      int i;
      i = 1,2,3;
      printf("i:%d\n",i);
      return 0;
}

Sortie: i = 1
Comme nous le savons, l'opérateur de virgule a une priorité inférieure à l'affectation.....

2
répondu Roopam 2015-07-04 13:31:23

Tout d'abord: la virgule n'est en fait pas un opérateur, pour le compilateur c'est juste un jeton qui a une signification dans le contexte avec d'autres jetons.

Qu'est-ce que cela signifie et pourquoi s'embêter?

Exemple 1:

Pour comprendre la différence entre la signification du même jeton dans un contexte différent, nous jetons un coup d'œil à cet exemple:

class Example {
   Foo<int, char*> ContentA;
}

Habituellement, un débutant en C++ penserait que cette expression pourrait / pourrait comparer les choses mais il est absolument faux, le sens de l'<, > et les jetons , dépendent du contexte d'utilisation.

L'interprétation correcte de l'exemple ci-dessus, c'est qu'il est un instatiation d'un modèle.

Exemple 2:

Lorsque nous écrivons une boucle typiquement for avec plus d'une variable d'initialisation et/ou plus d'une expression qui devrait être faite après chaque itération de la boucle, nous utilisons aussi des virgules:

for(a=5,b=0;a<42;a++,b--)
   ...

La signification de la virgule dépend du contexte d'utilisation, ici c'est le contexte de la for construction.

Qu'est une virgule dans le contexte signifie réellement?

Pour compliquer encore plus (comme toujours en C++) de l'opérateur virgule peut lui-même être surchargé (merci à Konrad Rudolph pour souligné).

Pour revenir à la question, le Code

a = b, c;

Signifie pour le compilateur quelque chose comme

(a = b), c;

Parce que la priorité du jeton/Opérateur = est supérieur à la priorité du jeton ,.

Et ceci est interprété dans le contexte comme

a = b;
c;

(notez que l'interprétation dépend du contexte, ici il ne s'agit ni d'un appel de fonction / méthode ni d'une instatiation de modèle.)

-2
répondu Quonux 2017-05-23 11:55:10