Qual è la syntax completa del ciclo “for” in C (e altri nel caso in cui siano compatibili)?

Ho visto alcuni strani loop for lettura del codice di altre persone. Ho cercato di cercare una spiegazione completa della syntax per il ciclo for in C ma è molto difficile perché la parola ” for ” appare in frasi non correlate rendendo la ricerca praticamente imansible per Google in modo efficace.

Questa domanda mi è venuta in mente dopo aver letto questo thread che mi ha fatto nuovamente incuriosire.

Il for qui:

 for(p=0;p+=(a&1)*b,a!=1;a>>=1,b<<=1); 

Nella condizione media c’è una virgola che separa i due pezzi di codice, cosa fa questa virgola? La virgola sul lato destro è comprensibile perché rende sia a>>=1 che un b<<=1 .

Ma all’interno di una condizione di uscita dal circuito, cosa succede? Esce quando p==0 , quando a==1 o quando entrambi si verificano?

Sarebbe bello se qualcuno potesse aiutarmi a capirlo e magari indirizzarmi verso una descrizione sintattica completa for loop.

La virgola non è esclusiva di cicli for; è l’operatore virgola.

 x = (a, b); 

farà prima a, poi b, quindi imposta x al valore di b.

La syntax per è:

 for (init; condition; increment) ... 

Il che è un po ‘(ignorando continue e break per ora) equivalente a:

 init; while (condition) { ... increment; } 

Quindi il tuo esempio di ciclo for è (sempre ignorando continue e break ) equivalente a

 p=0; while (p+=(a&1)*b,a!=1) { ... a>>=1,b< <=1; } 

Che agisce come se lo fosse (ignorando ancora continue e break ):

 p=0; while (true) { p+=(a&1)*b; if (a == 1) break; ... a>>=1; b< <=1; } 

Due ulteriori dettagli del ciclo for che non erano nella conversione semplificata in un ciclo while sopra:

  • Se la condizione è omessa, è sempre true (generando un ciclo infinito a meno che break , goto o qualcos'altro interrompano il ciclo).
  • Un continue agisce come se fosse un goto a un'etichetta appena prima dell'incremento, a differenza di un ciclo continue nel ciclo che salta l'incremento.

Inoltre, un dettaglio importante sull'operatore virgola: è un punto di sequenza, come && e || (che è il motivo per cui posso dividerlo in dichiarazioni separate e mantenere intatto il suo significato).


Cambiamenti in C99

Lo standard C99 introduce un paio di sfumature non menzionate in precedenza in questa spiegazione (che è molto buono per C89 / C90).

Innanzitutto, tutti i loop sono blocchi a sé stanti. In effetti,

 for (...) { ... } 

è esso stesso avvolto in un paio di parentesi graffe

 { for (...) { ... } } 

Lo standard dice:

ISO / IEC 9899: 1999 §6.8.5 Dichiarazioni di iterazione

¶5 Un'istruzione di iterazione è un blocco il cui ambito è un sottoinsieme rigoroso dell'ambito del blocco che lo racchiude. Il corpo del ciclo è anche un blocco il cui ambito è un sottoinsieme rigoroso dell'ambito dell'istruzione di iterazione.

Questo è anche descritto nel Razionale in termini di set aggiuntivo di parentesi graffe.

In secondo luogo, la parte init in C99 può essere una (singola) dichiarazione, come in

 for (int i = 0; i < sizeof(something); i++) { ... } 

Ora il "blocco avvolto attorno al ciclo" entra nel suo; spiega perché non è ansible accedere alla variabile al di fuori del loop. Puoi dichiarare più di una variabile, ma devono essere tutte dello stesso tipo:

 for (int i = 0, j = sizeof(something); i < j; i++, j--) { ... } 

Lo standard dice:

ISO / IEC 9899: 1999 §6.8.5.3 L'istruzione for

La dichiarazione

 for ( clause-1 ; expression-2 ; expression-3 ) statement 

si comporta come segue: L'espressione expression-2 è l'espressione di controllo che viene valutata prima di ogni esecuzione del corpo del ciclo. L'espressione expression-3 viene valutata come espressione di vuoto dopo ogni esecuzione del corpo del ciclo. Se la clausola 1 è una dichiarazione, l'ambito di tutte le variabili che dichiara è il resto della dichiarazione e l'intero ciclo, comprese le altre due espressioni; è raggiunto nell'ordine di esecuzione prima della prima valutazione dell'espressione di controllo. Se la clausola 1 è un'espressione, viene valutata come espressione di vuoto prima della prima valutazione dell'espressione di controllo. 133)

Sia la clausola 1 che l'espressione 3 possono essere omesse. Un'espressione omessa-2 viene sostituita da una costante diversa da zero.

133) Pertanto, la clausola 1 specifica l'inizializzazione per il ciclo, probabilmente dichiarando una o più variabili da utilizzare nel ciclo; l'espressione di controllo, espressione-2, specifica una valutazione effettuata prima di ogni iterazione, tale che l'esecuzione del ciclo continua fino a quando l'espressione non è uguale a 0; e expression-3 specifica un'operazione (come l'incremento) che viene eseguita dopo ogni iterazione.

La virgola separa semplicemente due espressioni ed è valida ovunque in C, dove è consentita un’espressione normale. Questi sono eseguiti in ordine da sinistra a destra. Il valore dell’espressione più a destra è il valore dell’espressione generale.

for cicli sono composti da tre parti, ognuna delle quali può anche essere vuota; uno (il primo) viene eseguito all’inizio e uno (il terzo) alla fine di ogni iterazione. Queste parti di solito inizializzano e incrementano un contatore, rispettivamente; ma possono fare qualsiasi cosa.

La seconda parte è un test che viene eseguito all’inizio di ogni esecuzione. Se il test produce false , il ciclo viene interrotto. Questo è tutto ciò che c’è da fare.

Lo stile C per ciclo è costituito da tre espressioni:

 for (initializer; condition; counter) statement_or_statement_block; 
  • L’inizializzatore viene eseguito una volta, all’avvio del ciclo.
  • La condizione viene verificata prima di ogni iterazione. Il ciclo viene eseguito finché dura il valore vero.
  • Il contatore viene eseguito una volta dopo ogni iterazione.

Ognuna di queste parti può essere un’espressione valida nella lingua in cui scrivi il loop. Ciò significa che possono essere utilizzate in modo più creativo. Tutto ciò che vuoi fare in anticipo può andare nell’inizializzatore, qualsiasi cosa tu voglia fare in mezzo può andare nella condizione o nel contatore, fino al punto in cui il ciclo non ha più corpo.

Per riuscirci, l’operatore virgola è molto utile. Ti consente di concatenare espressioni per formare un’unica singola espressione. Nella maggior parte dei casi viene utilizzato in questo modo in un ciclo for, le altre implicazioni dell’operatore virgola (ad esempio considerazioni sull’assegnazione del valore) giocano un ruolo secondario.

Anche se puoi fare cose intelligenti usando la syntax in modo creativo, non ne posso tenere conto finché non trovo una buona ragione per farlo. Giocare a golf con il codice for loops rende il codice più difficile da leggere e capire (e mantenere).

Anche la wikipedia ha un bell’articolo sul ciclo for .

Tutto è facoltativo in un ciclo for . Possiamo inizializzare più di una variabile, possiamo verificare più di una condizione, possiamo iterare più di una variabile usando l’operatore virgola.

Il seguente ciclo for ti porterà in un ciclo infinito. Stai attento controllando la condizione.

 for(;;) 

Konrad ha menzionato il punto chiave che vorrei ripetere: il valore dell’espressione più a destra è il valore dell’espressione generale.

Un compilatore Gnu ha dichiarato questo avviso quando ho inserito due test nella sezione “condition” del ciclo for

 warning: left-hand operand of comma expression has no effect 

Quello che intendevo veramente per la “condizione” erano due test con un “&&” tra. Per la dichiarazione di Konrad, solo il test sulla destra della virgola influenzerebbe la condizione.

il ciclo for è l’esecuzione per un tempo particolare per (;;)

il syntex per il ciclo

per(;;)

O

per (inizializzatore, condizione, contatore)

es. (rmv = 1; rmv < = 15; rmv ++)

esecuzione a 15 volte in per blocco

1.prima di inizializzare il valore perché avvia il valore

(es.) rmv = 1 o rmv = 2

La dichiarazione 2.seconda è test la condizione è vera o falsa, la condizione vera no.di esecuzione del tempo per il ciclo for e la condizione è false terminate per il blocco,

ad esempio i = 5; i < = 10 la condizione è vera

 i=10;i<10 the condition is false terminate for block, 

3. terzo è l'incremento o decremento

(es.) rmv ++ o ++ rmv