195 votes

Que fait l'opérateur "," en virgule en C?

Ce que fait le `` opérateur do en C ?

161voto

lillq Points 4161

L’expression :

Première expression1 est évaluée, alors expression2 n’est évaluée et la valeur d’expression2 est retournée pour l’expression entière.

142voto

crashmstr Points 15302

J’ai vu la plupart utilisée dans `` boucles :

 String s ; tout en (read_string(s), s.len() > 5) { //do quelque chose } 

Il va faire l’opération, puis faire un test basé sur un effet secondaire. L’autre façon serait de le faire comme ceci :

 String s ; read_string(s) ; while(s.Len() > 5) { //do quelque chose read_string(s) ; } 

44voto

Shafik Yaghmour Points 42198

L' opérateur virgule permettra d'évaluer l'opérande de gauche, jeter le résultat et d'en évaluer l'opérande de droite et qui sera le résultat. Le idiomatiques utiliser comme indiqué dans le lien est lors de l'initialisation des variables utilisées dans un for boucle, et il donne l'exemple suivant:

void rev(char *s, size_t len)
{
  char *first;
  for ( first = s, s += len - 1; s >= first; --s)
      /*^^^^^^^^^^^^^^^^^^^^^^^*/ 
      putchar(*s);
}

Sinon il n'y a pas beaucoup de grands usages de l' opérateur virgule, même si il est facile de l'abus de générer le code qui est difficile à lire et à maintenir.

À partir du projet de standard C99 la grammaire est comme suit:

expression:
  assignment-expression
  expression , assignment-expression

et l'alinéa 2 dit:

L' opérande de gauche d'un opérateur virgule est évalué comme un vide d'expression, il y a un point de séquence après son évaluation. Puis l' opérande de droite est évaluée; le résultat a son type et sa valeur. 97) Si une tentative est faite pour modifier le résultat d'un opérateur virgule ou d'y accéder après le prochain point de séquence, le comportement est indéfini.

Note de bas de page 97 dit:

Un opérateur virgule ne donnent pas une lvalue.

ce qui signifie que vous ne pouvez pas affecter le résultat de l' opérateur virgule.

30voto

Paul Stephenson Points 17507

L'opérateur virgule combine les deux expressions de chaque côté en un seul, de les évaluer à la fois de gauche à droite. La valeur de la main droite est retourné en tant que valeur de l'expression complète.

  • (expr1, expr2) , c'est comme (expr1 && expr2) mais les deux expr1 et expr2 seront toujours évaluées, quelle que soit expr1 de rendement.
  • (expr1, expr2) , c'est comme { expr1; expr2; } , mais il peut être utilisé comme une expression dans un appel de fonction ou de la cession.

Il est souvent vu en for boucles d'initialiser ou de maintenir de multiples variables comme ceci:

for (low = 0, high = MAXSIZE; low < high; low = newlow, high = newhigh)
{
    /* do something with low and high and put new values
       in newlow and newhigh */
}

En dehors de cela, je ne l'ai utilisé "en colère" dans les autres cas, lorsque l'emballage jusqu'à deux opérations qui devraient toujours aller de pair dans une macro. Nous avons eu code copié différentes valeurs binaires dans un tampon d'octets pour l'envoi sur un réseau, et un pointeur maintenue lorsque nous avons eu jusqu'à:

unsigned char outbuff[BUFFSIZE];
unsigned char *ptr = outbuff;

*ptr++ = first_byte_value;
*ptr++ = second_byte_value;

send_buff(outbuff, (int)(ptr - outbuff));

Où les valeurs ont été shorts ou ints nous l'avons fait:

*((short *)ptr)++ = short_value;
*((int *)ptr)++ = int_value;

Plus tard, nous avons lu que ce n'était pas vraiment valide en C, car (short *)ptr n'est plus une l-value et ne peut pas être incrémenté, bien que notre compilateur à la fois, n'a pas l'esprit. Pour résoudre ce problème, nous avons divisé l'expression en deux:

*(short *)ptr = short_value;
ptr += sizeof(short);

Cependant, cette approche se fondait sur tous les développeurs à se rappeler de mettre les deux états, dans tous les temps. Nous voulions une fonction où l'on pouvait passer le pointeur de sortie, la valeur et le type de la valeur. Ceci étant C, pas du C++ à l'aide de modèles, nous ne pourrions pas avoir une prise de fonction d'un type arbitraire, de sorte que nous nous sommes installés sur une macro:

#define ASSIGN_INCR(p, val, type)  ((*((type) *)(p) = (val)), (p) += sizeof(type))

En utilisant l'opérateur virgule, nous avons été en mesure de l'utiliser dans des expressions ou des énoncés comme nous l'avions souhaité:

if (need_to_output_short)
    ASSIGN_INCR(ptr, short_value, short);

latest_pos = ASSIGN_INCR(ptr, int_value, int);

send_buff(outbuff, (int)(ASSIGN_INCR(ptr, last_value, int) - outbuff));

Je ne dis pas que l'un de ces exemples sont un bon style! En effet, je crois me souvenir de Steve McConnell Code Complet de conseiller à l'encontre même de l'aide de la virgule opérateurs en for boucle: pour la lisibilité et la maintenabilité, la boucle doit être contrôlé par une seule variable, et les expressions dans l' for ligne elle-même ne doit contenir que la boucle de contrôle de code, pas d'autres morceaux de l'initialisation ou de la boucle de l'entretien.

8voto

Ben Collins Points 11318

Entraîne l’évaluation de plusieurs instructions, il utilise seulement le dernier d'entre eux comme une valeur résultante (rvalue, je crois).

Alors...

devrait se traduire par x étant la valeur 8.

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