Il ciclo "for".

Passate ore con il comando da me preferito lo "IF". Nidificati, intersecati, frullati e tritati, ore a scovare la parentesi graffa che di sua spontanea volontà si è spostata, ore ed imprecazioni per il punto e virgola che cambia sesso e diventa un due punti e alla fine ti rilassi... ora; serve solo il solito ciclo "For" per popolare un' array. Copio da uno scratch preesistente e lo incollo, non voglio sbagliare. Stanco ma, la sponda è ormai prossima, un ultimo tocco al ciclo "for" banale banale, ovvero un conteggio alla rovescia ed ecco... Non funziona! Mi sono incavolato. Lo permutato in tutte le forme possibili tanto da scoprire nuove forme di programmazione e finalmente anche quella funzionante ma, sono a chiedervi:<< sapreste spiegarmi perchè quelle che non funzionano cosa hanno di realmente errato? Quale logica (se esiste) si nasconde dietro un ciclo "FOR"?>>. Segue il codice, alcune parti vanno decommentate per essere eseguite.
Grazie per la Vs. pazienza.
P.S.
Approfitto qui per porre un'ulteriore quesito:
C'è modo di vedere il codice sorgente preprocessato ma prima della compilazione a codice oggeto completo delle parti importate dalle librerie?

void setup() {
  Serial.begin(4800);
  while (!Serial) {}
  /*
     Segue il classico ciclo "for" incrementale(FUNZIONA!)
  */
  for (byte i = 0; i <= 100; i++) {                //A
    Serial.print(" A=");
    Serial.print(i);
  }
  Serial.println("A");
  /*
    Segue una leggera variante al classico ciclo "for" incrementale. Variato: "i++ con ++i" (FUNZIONA!)
  */
  for (byte i = 0; i <= 100; ++i) {                //B
    Serial.print(" B=");
    Serial.print(i);
  }
  Serial.println("B");
  /*
    Come sopra. Variato: "i<=100 con i==100" (NON FUNZIONA...??)
  */
  //for (byte i = 0; i == 100; ++i) {                //C
  //  Serial.print(" C=");
  //  Serial.print(i);
  //}
  Serial.println("C");
  /*
    Come il caso 'B'. Variato: "i<=100 con i>=100" (NON FUNZIONA...??)
  */
  // for (byte i = 0; i >= 100; ++i) {                //D
  //  Serial.print(" D=");
  //    Serial.print(i);
  //  }
  Serial.println("D");
  /*
    Come il caso 'B' ma rovesciati i termini. Previsto un conteggio decrementale. (FUNZIONA! MA IMPAZZISCE...)
  */
  // for (byte i = 100; i >= 0; --i) {                //E
  //   Serial.print(" E=");
  //   Serial.print(i);
  //  }
  Serial.println("E");
  /*
    Come sopra previsto un conteggio decrementale.Variato ">=i con <=i" (NON FUNZIONA...??)
  */
  // for (byte i = 100; i <= 0; --i) {                //F
  //   Serial.print(" F=");
  //   Serial.print(i);
  // }
  Serial.println("F");
  /*
    Come nel caso "E" previsto un conteggio decrementale.Dichiarata una variabile "int" al posto di byte (FUNZIONA!)
  */
  for (int i = 100; i >= 0; --i) {              //G
    Serial.print(" G=");
    Serial.print(i);
  }
  Serial.println("G");
  /*
    Come sopra.Dichiarata una variabile "unsigned int" al posto di int (FUNZIONA! MA IMPAZZISCE...)
  */
  for (unsigned int i = 100; i >= 0; --i) {              //H
    Serial.print(" H=");
    Serial.print(i);
  }
  Serial.println("H");
} void loop() {}

invece di fare tutte quelle prove facevi prima e consumavi meno dita a cercare la descrizione di for magari sul santo, o chiedere alla santa hawaiana....
comunque il for si puo' riscrivere
un

for (inizio; test; incremento){comandi}

si puo' riscrivere

inizio
while (test)
{comandi
Incremento}
end

così è piu' chiaro?
no? santa hawaiana o un buon manuale di 'C'

"end" andrebbe chiamato "incremento" e soprattutto messo DENTRO alle graffe.

Vero è
Correggo subito

tek-0:
perchè quelle che non funzionano cosa hanno di realmente errato?

Il for continua finché la condizione è vera, nelle forme che non funzionano la condizione è falsa in partenza.

L'ultimo caso non è che impazzisce, le variabili unsigned decrementate non vanno mai sotto zero, ripartono dal loro valore massimo (in questo caso 65535), quindi in questo caso la condizione risulta sempre vera e il ciclo non termina mai.

Standardoil:
invece di fare tutte quelle prove facevi prima e consumavi meno dita a cercare la descrizione di for magari sul santo, o chiedere alla santa hawaiana....
comunque il for si puo' riscrivere
un

for (inizio; test; incremento){comandi}

si puo' riscrivere

inizio
while (test)
{comandi
Incremento}
end

così è piu' chiaro?
no? santa hawaiana o un buon manuale di 'C'

Non è stato molto chiaro lo spirito del messaggio... Se volevo soluzioni pronte all'uso, ne trovavo a tonnellate e gia prima di cercarle a quel punto avrei cercato il software già pronto all'uso in uno dei tanti siti che mettono a disposizione elaborati già pronti. Libri? ne ho letti parecchi e ne possiedo parecchi ma, a volte la soluzione soprattutto per un neofita del "C" come me non emerge sempre in maniera spontanea e quindi, la sperimentazione, i tentativi ripetuti credo sia una strada quasi scontata volendo imparare. Concludendo, desideravo una qualche idea sul comportamento del comando "FOR" dato che, davo per scontato il suo funzionamento e sopratutto data la mia scarsa dimestichezza e la strana anomalia (dal mio punto di vista) a riguardo dei casi in cui nel ciclo inserisco variabili forzatamente senza segno.

Claudio_FF:
Il for continua finché la condizione è vera, nelle forme che non funzionano la condizione è falsa in partenza.

L'ultimo caso non è che impazzisce, le variabili unsigned decrementate non vanno mai sotto zero, ripartono dal loro valore massimo (in questo caso 65535), quindi in questo caso la condizione risulta sempre vera e il ciclo non termina mai.

Grazie per l'attenzione, ciò che ancora non mi è chiaro è il costrutto, la lolgica di funzionamento. Dgli esempi da me postati, ci sono i tre casi funzionanti, come incremento i casi "A" e "B" e usano i limiti 0 e 100 per la variabile byte. Nel caso "G" la funzione è decrementale gli estremi valgono 100 e 0, ma da quanto emerge sono costretto ad usare una variabile a 16 bit con segno pena un non funzionamento per il motivo da te indicato ma non ancora chiaro per la costrizione nell'uso di variabili con segno.

no
sicuramente funziona

for(int x=100;x>=0;x--)

la scelta del tipo di variabile dipende dal numero che deve contenere
sicuramente

for (byte x=400;x>=0;x--)

non funziona perchè byte è un unsigned e può avere valori da 0 a 255

quello che ti diceva Standardoil era che cliccando su resources (sulla fascia verde in alto alla pagina), poi su references ed infine nel menù a sinistra su structure trovi il comando for che dice

Syntax

for (initialization; condition; increment) {
//statement(s);
}

The initialization happens first and exactly once. Each time through the loop, the condition is tested; if it’s true, the statement block, and the increment is executed, then the condition is tested again. When the condition becomes false, the loop ends.

per cui

for (byte i = 100; i <= 0; --i)

non funziona perchè i non è uguale/inferiore a 0 alla prima analisi per cui il ciclo viene interrotto

Quel che tutti stanno cercando di dirti, tra le righe, è il for non ha nulla di strano. C'è una fase di inizializzazione, una sequenza di istruzioni che si ripetono finché una condizione è vera e infine una fase di incremento eseguita al termine della sequenza di istruzioni, alla fine di ogni ripetizione. Fine, non c'è altro.

Quel che ti sta traendo in inganno è invece l'aritmetica modulare:

for (unsigned int i = 100; i >= 0; --i) {
}

Ora, è chiaro che i parte da 100. Viene valutata la condizione: 100 >= 0, quindi viene eseguito il blocco di istruzioni. Poi avviene l'"incremento", che in questo caso è in realtà un decremento: i = 100 - 1, quindi i = 99. Viene rivalutata la condizione: 99 >= 0, quindi si ripete il blocco, ecc ecc...

Questo ovviamente avviene per circa 100 volte, poi vediamo cosa succede quando i arriva a valere 1: al momento del decremento i = 1 - 1 = 0. La condizione 0 >= 0 è ancora vera, quindi si ripete ancora una volta il blocco. Siamo di nuovo al decremento: i = 0 - 1, qua tu ti aspetti che i vada a valere -1, ma non è così, perché la tua variabile è espressamente dichiarata unsigned, quindi senza segno, e non può diventare negativa. Per le proprietà dell'aritmetica binaria modulare, ti dico io che succederà che i = 65535. Ovviamente 65535 >= 0, quindi il ciclo si ripete ancora, poi i verrà decrementata e il ciclo continuerà, ma non succederà MAI che i non sia >= 0, data la mancanza di segno della variabile, per cui di fatto non uscirai MAI dal ciclo.

Ma, ribadisco, questo ha poco a che vedere col for, sei TU che hai deciso di dichiarare la tua variabile unsigned, e sei TU che devi gestirla in maniera sensata. Devi studiare l'aritmetica binaria, la sua modularità e le limitazioni numeriche dei vari tipi.

SukkoPera:
Quel che tutti stanno cercando di dirti, tra le righe, è il for non ha nulla di strano. C'è una fase di inizializzazione, una sequenza di istruzioni che si ripetono finché una condizione è vera e infine una fase di incremento eseguita al termine della sequenza di istruzioni, alla fine di ogni ripetizione. Fine, non c'è altro.

Quel che ti sta traendo in inganno è invece l'aritmetica modulare:

for (unsigned int i = 100; i >= 0; --i) {

}




Ora, è chiaro che i parte da 100. Viene valutata la condizione: 100 >= 0, quindi viene eseguito il blocco di istruzioni. Poi avviene l'"incremento", che in questo caso è in realtà un decremento: i = 100 - 1, quindi i = 99. Viene rivalutata la condizione: 99 >= 0, quindi si ripete il blocco, ecc ecc...

Questo ovviamente avviene per circa 100 volte, poi vediamo cosa succede quando i arriva a valere 1: al momento del decremento i = 1 - 1 = 0. La condizione 0 >= 0 è ancora vera, quindi si ripete ancora una volta il blocco. Siamo di nuovo al decremento: i = 0 - 1, qua tu ti aspetti che i vada a valere -1, ma non è così, perché la tua variabile è espressamente dichiarata *unsigned*, quindi *senza segno*, e [u]non può diventare negativa[/u]. Per le proprietà dell'aritmetica binaria modulare, ti dico io che succederà che i = 65535. Ovviamente 65535 >= 0, quindi il ciclo si ripete ancora, poi i verrà decrementata e il ciclo continuerà, ma non succederà MAI che i non sia >= 0, data la mancanza di segno della variabile, per cui di fatto [u]non uscirai MAI dal ciclo[/u].

Ma, ribadisco, questo ha poco a che vedere col *for*, sei TU che hai deciso di dichiarare la tua variabile unsigned, e sei TU che devi gestirla in maniera sensata. Devi studiare l'aritmetica binaria, la sua modularità e le limitazioni numeriche dei vari tipi.

Grazie per la chiara ed esaustiva spigazione, ora non devo far altro che rivedere i vari casi testati.

... detta molto semplicemente, "i>=1" invece che "i>=0" risolve il problema alla radice ... :wink:

EDIT: per l'altra tua condizione non funzionante, quella con "i==100" ... e' di nuovo un problema di "interpretazione logica", diciamo cosi ... quando usi >=100, dici al ciclo di eseguire "finche' i e' o maggiore o uguale a 100" ... per cui, qualsiasi numero inferiore a 100 esegue l'istruzione ... ma con ==100, gli stai dicendo di eseguire "solo se i e' esattamente 100", per cui qualsiasi numero diverso da 100, inferiore o superiore che sia, termina il ciclo ... :wink:

Alla fine si! la soluzione banale era porre i>=1, visivamente il ciclo è speculare al ciclo incremento unico neo ho dovuto integrare un'istruzione in più per aver la variabile "i" a 0 ma non importa sono io che decido e non il processore! :wink:

Potevi semplicemente togliere l'unsigned, eh...

Anche su i libri di testo la spiegazione delle strutture di controllo è breve, un po spiegato e mostrato il funzionamento non c'è altro da dire.

Un po come chiedere gli ingredienti della pizza margherita e poi essere delusi perché la spiegazione è breve :slight_smile:

SukkoPera:
Potevi semplicemente togliere l'unsigned, eh...

No la risposta me l'hai data tu... Dovevo vedere l'inghippo, l'inatteso cambio di segno della variabile( perchè ho dato per scontato quella riga di codice). Alla fine è rimasto il byte come previsto e il ciclo ha acquistato la seguente forma:

Serial.print(F(" Registro[1]: "));
for (byte i = 8; i >= 1; --i) {
Serial.print(bitRead(Registro[1], i - 1));
}

Sempre un byte e non di più... :wink:

Io ti ho detto di studiarti qualcosa, tu non l'hai fatto e sei convinto di avere capito cose che in realtà non hai capito.

Perché byte altro non è che un unsigned char sotto mentite spoglie.

SukkoPera:
Io ti ho detto di studiarti qualcosa, tu non l'hai fatto e sei convinto di avere capito cose che in realtà non hai capito.

Perché byte altro non è che un unsigned char sotto mentite spoglie.

:smiley:

Reference > Language > Variables > Data types > Byte
byte
[Data Types]
Description

A byte stores an 8-bit unsigned number, from 0 to 255.

Non vorrei sembrare arrogante, ma ho la sensazione che non si legga con sufficiente attenzione ciò che la controparte scrive (forse troppo presi nel rispondere a troppi "post" contemporanemente). il fatto che "byte" fosse senza segno era scontato, il problema verteva sul non avevo valutato (come gia avevo scritto ma ...) che la variabile, andasse negativa nel ciclo. Per chiudere questo post, aggiundo che alla fine ho comunque optato per sostituire il ciclo con la conversione diretta in binario. Ma questo è un'altro discorso...
Serial.print(Registro[n],BIN);
Ciao :slight_smile: