[RISOLTO] Dubbio funzione for

Ciao a tutti, c'è qualcuno di buona volontà che mi potrebbe spiegare questa riga di codice, o meglio, ho capito che pone la variabile i a 0 poi dice, finchè i è minore di 255.....ecco, l'ultima parte non l'ho capita.

for( int i = 0 ; i < 255 ; i += 1 ){

Grazie
Leo

Incrementa i. Solitamente si scrive i++ o ++i (con significato leggermente diverso ma non in questo contesto), ma i += 1 è una forma equivalente.

PS: for è un'istruzione, non una funzione.

Perfetto, grazie mille!

Leo

Se non ho capito male variabile segno = numero é come dire variabile= variabile segno numero

Gli operatori di incremento e decremento i++ i-- , dovrebbero corrispondere a un codice macchina più semplice "mi pare un unica istruzione", per cui sono da preferire.
Nei cicli for() a volte capita di dover incrementare di valori superiori all'unità, allora in quel caso si usa +=.

In definitiva se devi incrementare di uno è meglio usare i++ , se devi incrementare di valori superiori allora

usi += :slight_smile: :slight_smile:

torn24:
Gli operatori di incremento e decremento i++ i-- , dovrebbero corrispondere a un codice macchina più semplice ...

... oggigiorno qualsiasi compilatore un po' furbo (e gcc è piuttosto furbo) tratta i+=1 come i++. :wink:

Guglielmo

Buono a sapersi Guglielmo :slight_smile:

Era una cosa che avevo letto da qualche parte! Dove diceva che alcune istruzioni del C venivano tradotte in un unica istruzione in assembly, e faceva proprio l'esempio degli operatori di incremento :slight_smile:
Ma non conosco l'assembly e non ho mai visionato il codice assembly di un codice C...

torn24:
Era una cosa che avevo letto da qualche parte! Dove diceva che alcune istruzioni del C venivano tradotte in un unica istruzione in assembly ...

Vero, ma devi sempre considerare le altre istruzioni che servono a recuperare la variabile e poi a salvarla, quindi, un banale i++ o i+=1 (ma rimane valido per qualsiasi valore), ottimizzando al massimo, con una variabile di tipo intero non segnata comporta comunque cinque istruzioni assembler ...

lds r24, 0x0100   // recupera il primo byte dell'intero e lo mette in r24
lds r25, 0x0101   // recupera il secondo byte dell'intero e lo mette in r25
adiw r24, 0x01    // somma il valore 1 alla word che ora si trova in r24 e r25
sts 0x0101, r25   // salva il secondo byte da r25
sts 0x0100, r24   // salva il primo byte da r24

... come vedi, l'incremento (o la somma di un valore) è effettivamente fatto con una singola istruzione macchina, ma intorno c'è dell'altro e alla fine, comunque, almeno 5 istruzioni devi fare.

Guglielmo

Voglio sperare che un compilatore furbo:

  • Si renda conto che basta un byte per rappresentare tutti i valori assunti dalla variabile
  • La mantenga in un registro all'interno del for (a meno di necessità particolari)

>SukkoPera: il caso riportato NON è relativo ad un ciclo for, ma alle due operazioni indicate. Quanto all'ampiezza dell'indice è l'utente che lo impone dichiarando la variabile del for, NON il compilatore ... se gli dici che i è int e poi vai solo da 0 a 255 userà sempre e comunque 2 bytes del int che hai dichiarato e non 1 ... ::slight_smile:

Guglielmo

Sì, ma in un caso come quello proposto, in cui 0 <= i <= 255, e supponendo che i non venga modificato all'interno del loop, non vedo perché un compilatore non possa rendersi conto che basta un singolo byte e ottimizzare!

>Sukkopera: non ottimizza, rispetta le scelte dell'utente ...

Preso un programmino stupido come questo:

volatile int a;
int i;

void setup() __attribute__((optimize("-O3")));
void setup() {
  // put your setup code here, to run once:
  
  for(i=0; i<255;i++) {
   a += i;
  }
}

void loop() {
  // put your main code here, to run repeatedly:

}

in cui ho:

  1. forzato l'aggiornamneto di 'a' dichiarandola 'volatile' (altrimenti il compilatore che è furbo, vendendo che non era utilizzato nulla, buttava tutto)
  2. per il setup() ho richiesto il massimo dell'ottimizzazione per la velocità (-O3)

... produce il seguente assembler:

00000090 <setup>:
  90:	80 e0       	ldi	r24, 0x00	; 0
  92:	90 e0       	ldi	r25, 0x00	; 0
  94:	20 91 00 01 	lds	r18, 0x0100
  98:	30 91 01 01 	lds	r19, 0x0101
  9c:	28 0f       	add	r18, r24
  9e:	39 1f       	adc	r19, r25
  a0:	30 93 01 01 	sts	0x0101, r19
  a4:	20 93 00 01 	sts	0x0100, r18
  a8:	01 96       	adiw	r24, 0x01	; 1
  aa:	8f 3f       	cpi	r24, 0xFF	; 255
  ac:	91 05       	cpc	r25, r1
  ae:	91 f7       	brne	.-28     	; 0x94 <setup+0x4>
  b0:	90 93 03 01 	sts	0x0103, r25
  b4:	80 93 02 01 	sts	0x0102, r24
  b8:	08 95       	ret

... dove, come puoi ben vedere, usa per la variabile 'i' intera i due registri r24 e r25 che inizializza a zero, effettua una add word di 1 sul numero che sta a partire da r24 e effettua il compare con il 255.

Guglielmo

Uhm, ma questo è perché all'interno del for deve sommare i con a che è comunque un int.

Prova una cosa tipo:

for(i=0; i<255;i++) {
   Serial.println("Ciao");
}

Ovvio che SI ...
... se difatti dichiari la variabile 'a' di un byte e lasci 'i' come int, l'assembler equivalente, nel for, è ottimizzato ad utilizzare solo il byte meno significativo dell'int (che comunque è e resta un int) che gli basta e gli avanza :wink:

Insomma ... dipende molto dal programma, anche se tu vai solo fino a 255, ma coinvolgi nelle operazioni qualche cosa di più grande di un byte, lui, pur sapendo che arriva sino a 255, utilizza tutto l'int, se invece coinvolgi un byte, allora usa solo quello che serve :slight_smile:

Guglielmo

Ah beh, certo! È quello che intendevo con questo:

SukkoPera:
Sì, ma in un caso come quello proposto, in cui 0 <= i <= 255, e supponendo che i non venga modificato all'interno del loop, non vedo perché un compilatore non possa rendersi conto che basta un singolo byte e ottimizzare!

Dove però "modificato" non era la parola giusta. :cold_sweat:

Io parlo adesso senza aver avuto occasione di controllare la documentazione
Però credo che il compilatore se ottimizzasse, in particolare il programma del pst 11 sbaglierebbe alla grande
Quelle variabili sono extern, per il compilatore potrebbero essere usate in file sorgente non ancora compilati, o peggio in oggetti pre-compilati, e il linker ha (avrebbe) bisogno di trovare una variabile del tipo corretto
Che poi lo IDE di Arduino non ne faccia uso è parrocchia differente.....