Domanda

Che cosa fa l' , operatore in C?

È stato utile?

Soluzione

L'espressione:

(expression1,  expression2)

Prima expression1 è valutata, espressione2 è valutato, e il valore di espressione2 restituito per l'intera espressione.

Altri suggerimenti

Ho visto più utilizzati while loop:

string s;
while(read_string(s), s.len() > 5)
{
   //do something
}

Si farà l'operazione, poi fare un test basato su un lato-effetto.L'altro modo sarebbe quello di fare in questo modo:

string s;
read_string(s);
while(s.len() > 5)
{
   //do something
   read_string(s);
}

Il operatore virgola valuterà l'operando di sinistra, scarta il risultato e quindi valutare l'operando di destra e che sarà il risultato.Il idiomatiche utilizzare come indicato nel link è quando l'inizializzazione delle variabili utilizzate in un for loop, e fornisce il seguente esempio:

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

Altrimenti non ci sono molti grande utilizza la operatore virgola, anche se è facile abuso per generare il codice difficile da leggere e conservare.

Dal progetto di standard C99 la grammatica è come segue:

expression:
  assignment-expression
  expression , assignment-expression

e paragrafo 2 dice:

Il operando di sinistra di un operatore virgola viene valutato come un vuoto di espressione; c'è una sequenza in punto dopo la valutazione.Quindi il operando di destra è valutato;il risultato ha il suo tipo e valore. 97) Se si tenta di modificare il risultato di una virgola operatore o per l'accesso dopo la sequenza successiva punto, il comportamento è indefinito.

Nota a piè di pagina 97 dice:

Un operatore virgola fa non produrre un lvalue.

il che significa che non è possibile assegnare il risultato di operatore virgola.

È importante notare che l'operatore virgola ha il precedenza minore e quindi ci sono casi in cui l'utilizzo () può fare una grande differenza, per esempio:

#include <stdio.h>

int main()
{
    int x, y ;

    x = 1, 2 ;
    y = (3,4) ;

    printf( "%d %d\n", x, y ) ;
}

avrà il seguente output:

1 4

L'operatore virgola unisce le due espressioni entrambi i lati di esso in uno solo, valutando sia da sinistra che a destra.Il valore di destra viene restituito come valore dell'intera espressione. (expr1, expr2) è come { expr1; expr2; } ma è possibile utilizzare il risultato di expr2 in una chiamata di funzione o di assegnazione.

Si è spesso visto in for passanti per avviare o mantenere più variabili come questo:

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 */
}

A parte questo, l'ho usata solo "rabbia" in un altro caso, quando il confezionamento di due operazioni che devono sempre andare insieme in una macro.Abbiamo avuto il codice copiato i vari valori binari in un buffer di byte per l'invio in rete, e un puntatore mantenuta in cui abbiamo avuto fino a:

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

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

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

Dove i valori sono stati shorts o ints abbiamo fatto questo:

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

Poi leggiamo che questo non era davvero valido C, perché (short *)ptr non è più un l-value e non può essere incrementato, anche se il nostro compilatore al momento non mente.Per risolvere questo problema, abbiamo diviso l'espressione in due:

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

Questo approccio, tuttavia, invocata tutti gli sviluppatori ricordando di mettere entrambe le affermazioni in tutto il tempo.Abbiamo voluto una funzione in cui è possibile passare il puntatore all'uscita, il valore e il valore del tipo.Essendo questa la C, non C++ con i modelli, non potevamo avere una funzione di prendere un tipo arbitrario, così abbiamo optato per una macro:

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

Utilizzando l'operatore virgola siamo stati in grado di usare espressioni o delle dichiarazioni come avremmo voluto:

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));

Non sto suggerendo di uno qualsiasi di questi esempi sono un buon stile!Anzi, mi sembra di ricordare Steve McConnell Il Codice Completo consulenza contro anche usando la virgola operatori, in un for loop:per migliorare la leggibilità e manutenibilità, il ciclo deve essere controllato da una sola variabile, e le espressioni in for stessa linea deve contenere solo ciclo-codice di controllo, non di altri bit extra di inizializzazione o il ciclo di manutenzione.

Essa provoca la valutazione di più dichiarazioni, ma utilizza solo l'ultimo come valore risultante (rvalue, credo).

Quindi...

int f() { return 7; }
int g() { return 8; }

int x = (printf("assigning x"), f(), g() );

dovrebbe portare a x essere impostato a 8.

L'operatore virgola non fa nulla di significativo, si tratta di un 100% di superfluo funzione.L'utilizzo principale è "la gente cercando di essere intelligente" e quindi utilizzarlo per (involontariamente) di offuscare il codice leggibile.Il principale ambito di utilizzo è quello di offuscare per i passanti, per esempio:

for(int i=0, count=0; i<x; i++, count++)

Dove int i=0, count=0 in realtà non è l'operatore virgola, ma una dichiarazione elenco (siamo già confuso qui). i++, count++ è l'operatore virgola, che valuta l'operando di sinistra prima e poi l'operando di destra.Il risultato dell'operatore virgola è il risultato dell'operando di destra.Il risultato dell'operando di sinistra è scartato.

Ma il codice di cui sopra potrebbe essere scritto in un modo molto più leggibile, senza l'operatore virgola:

int count = 0;
for(int i=0; i<x; i++) // readable for loop, no nonsense anywhere
{
  ...
  count++;
}

L'unico reale utilizzo dell'operatore virgola che ho visto, è artificiale discussioni sulla sequenza di punti, in quanto l'operatore virgola viene fornito con una sequenza di scegliere tra la valutazione di destra e di sinistra operandi.

Quindi, se avete qualche comportamento indefinito codice come questo:

printf("%d %d", i++, i++);

Si può effettivamente girare in solo non specificato comportamento (ordine di valutazione dei parametri di funzione) scrivendo

printf("%d %d", (0,i++), (0,i++));

Ora c'è una sequenza di punto tra ogni valutazione di i++, così almeno non rischio di crash e bruciare più a lungo, anche se l'ordine di valutazione dei parametri di funzione rimane indeterminata.

Naturalmente nessuno potrebbe scrivere codice in applicazioni reali, è utile solo per la lingua, l'avvocato discussioni sulla sequenza di punti in linguaggio C.

L'operatore virgola è vietato dalla MISRA-C:2004 e MISRA-C:2012, con la motivazione che crea meno leggibile il codice.

Come in precedenza, le risposte hanno indicato, si valuta tutte le istruzioni, ma utilizza quest'ultimo come il valore dell'espressione.Personalmente ho trovato utile in loop espressioni:

for (tmp=0, i = MAX; i > 0; i--)

L'unico posto che ho visto essere utile è quando dovete scrivere un funky ciclo in cui si desidera fare più cose in una delle espressioni (probabilmente init espressione o espressione del loop.Qualcosa di simile a:

bool arraysAreMirrored(int a1[], int a2[], size_t size)
{
  size_t i1, i2;
  for(i1 = 0, i2 = size - 1; i1 < size; i1++, i2--)
  {
    if(a1[i1] != a2[i2])
    {
      return false;
    }
  }

  return true;
}

Perdonatemi se ci sono errori di sintassi o se ho mescolato in qualcosa che non è rigoroso C.Non sto sostenendo che l'operatore è in buona forma, ma è quello che si potrebbe utilizzare per.Nel caso di sopra, probabilmente sarei utilizzare un while loop invece così le molteplici espressioni di init e ciclo potrebbe essere più evidente.(E vorrei inizializzare i1 e i2 inline invece di dichiarare e quindi l'inizializzazione....bla bla bla.)

Sto rivivere tutto questo è sufficiente per affrontare le questioni da @Rajesh e @JeffMercado che ritengo molto importante in quanto questo è uno dei migliori motori di ricerca successi.

Prendere il seguente frammento di codice, ad esempio

int i = (5,4,3,2,1);
int j;
j = 5,4,3,2,1;
printf("%d %d\n", i , j);

Verrà stampata

1 5

Il i caso viene gestito come spiegato dalla maggior parte delle risposte.Tutte le espressioni vengono valutate da sinistra a destra, ma solo l'ultima è assegnato a i.Il risultato del ( espressione )is1`.

Il j caso segue le regole di precedenza in quanto , ha il più basso di precedenza degli operatori.A causa di tali norme, il compilatore vede assegnazione di espressione, costante, costante ....Le espressioni sono nuovamente valutati da sinistra a destra e i loro effetti collaterali rimanere visibile, pertanto, j è 5 come risultato di j = 5.

Interstingly, int j = 5,4,3,2,1; non è consentito il linguaggio spec.Un inizializzatore si aspetta un assegnazione di espressione in modo diretto , l'operatore non è consentito.

Spero che questo aiuta.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top