Rovereto
Offline
Jr. Member
Karma: 1
Posts: 80
|
 |
« on: February 27, 2013, 08:34:48 am » |
Buongiorno a tutti! Modificando il codice di uno sketch per gestire 3 linee di luci mi sono imbattuto nell'ancestrale dubbio sull'utilizzo dei puntatori. Inizialmente globalmente venivano dichiarate 3 variabile distinte per le 3 linee di luci : (es. On1,On2,On3); Per rendere tutto intuitivo e pratico ho deciso di sostituirle con degli array (es. On[2],Off[2] ...) Il problema è che sostituendo i parametri nelle funzioni sembra che non sia possibile modificare le variabili globali negli array... Prima le variabili venivano passate cosi... byte On1, On2 On3;
void loop(){
funzione (&On1,&On2,&On3); }
funzione (byte *O1, byte *O2, byte *O3){ O1=1; O2=2; O3=3; }
Mente volevo modificarle in byte On[2];
void loop(){ funzione (0); }
funzione (byte n){ On[n]=1; On[n+1]=2; On[n+2]=3; }
Tutti e due i metodi dovrebbero modificare le variabili a livello globale giusto? è la stessa cosa che scrivere ? byte On1, On2 On3;
void loop(){
funzione (On1,On2,On3); }
funzione (byte &O1, byte &O2, byte &O3){ O1=1; O2=2; O3=3; }
Spero di essermi spiegato bene.. perche nel caso degli array sembra non funzioni come dovrebbe: non modifica la variabile globalmente.. Buona giornata a tutti!
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Tesla Member
Karma: 87
Posts: 8493
:(){:|:&};:
|
 |
« Reply #1 on: February 27, 2013, 08:48:17 am » |
esempio N°1 errato: funzione (byte *O1, byte *O2, byte *O3){ O1=1; O2=2; O3=3; } così stai cambiando gli INDIRIZZI dei puntatori O1, O2 e O3 con i valori 1, 2 e 3. Tu vuoi cambiare i valori quindi ci va il * davanti (notare le parentesi, l'= ha prioristà rispetto a * !): funzione (byte *O1, byte *O2, byte *O3){ (*O1)=1; (*O2)=2; (*O3)=3; } oppure, visto che array e puntatori sono la stessa cosa, puoi considerare il puntatore ad una variabile come un array di dimensione 1: funzione (byte *O1, byte *O2, byte *O3){ O1[0]=1; O2[0]=2; O3[0]=3; } Quindi dire (*puntatore)=x o puntatore[0] = x è la stessa cosa! invece il seguente che io sappia non ha senso, non dovrebbe nemmeno compilare: funzione (byte &O1, byte &O2, byte &O3){
|
|
|
|
« Last Edit: February 27, 2013, 08:57:38 am by lesto »
|
Logged
|
|
|
|
|
Offline
God Member
Karma: 3
Posts: 602
"La teoria è quando si sa tutto ma non funziona niente. La pratica è quando funziona tutto ma non si sa il perché. In ogni caso si finisce sempre con il coniugare la teoria con la pratica: non funziona niente e non si sa il perché." Albert Einstein
|
 |
« Reply #2 on: February 27, 2013, 08:49:26 am » |
Per prima cosa, essendo globali non importa che le passi come riferimento, funziona anche così: byte On1, On2, On3;
void loop() { funzione (); }
funzione () { O1=1; O2=2; O3=3; } Seconda cosa: quando definisci un array dentro le quadre devi mettere il numero di elementi, quindi variabile[3] sarà formata dagli elementi variabile[0], variabile[1], variabile[2]. Attenzione, nessuno ti vieta di andare a leggere/scrivere variabile[3] ma non sai cosa c'è, potresti fare danno (a livello software, chiaramente). Terza cosa: il c++ tratta gli array come puntatori, quindi se crei un array variabile[3] lui ti crea un puntatore al primo elemento della lista. Per trovare un elemento della lista lui fa questa cosa: variabile[2] = *(variabile+2) A questo punto ti svelo un segreto del c++: variabile[2] = *(variabile+2) = *(2+variabile) = 2[variabile] E' un "baco" intrinseco del c++ per come tratta gli array... 
|
|
|
|
|
Logged
|
|
|
|
|
MC
Offline
God Member
Karma: 9
Posts: 676
|
 |
« Reply #3 on: February 27, 2013, 08:51:59 am » |
Ciao, funzione (byte &O1, byte &O2, byte &O3)
Cosa intenderesti fare con questa funzione ? Se la tua idea era accettare dei parametri di tipo puntatore avresti dovuto mettere funzione A(byte * O1, byte * O2, byte * O3) { // corpo della funzione }
e chiamando quella funzione invece avresti dovuto mettere A(&On1,&On2,&On3);
Perchè tutto ciò? Semplice, nella firma della funzione specifici che il tipo di dato che passi, non èun byte, ma un puntatore ad un valore di quel tipo, e lo fai mettendo il simbolo * Quando invece vai a richiamare quella funzione, devi indicare che non vuoi passare il valore della tua variabile On1,On2,On3 , ma bensi l'indirizzo di memoria in cui questa è stata allocata, pertanto devi mettere il simbolo & In parole povere : funzione A(byte * O1, byte * O2, byte * O3) { // corpo della funzione } significa che la tua funzione si aspetta di trovare 3 puntatori a byte come parametri (e attenzione poi a come li usi all'interno della funzione stessa!!) e A(&On1,&on2,&On3) equivale a : Chiama la funzione A passando L'INDIRIZZO DI MEMORIA di On1,L'INDIRIZZO DI MEMORIA di On2,L'INDIRIZZO DI MEMORIA di On3 Spero di averti chiarito. Comunque il problema che lamenti per l'array globale non esiste, sicuramente hai fatto confusione . Se passi alla funzione il puntatore corretto all'array, riesci tranquillamente a variarne il suo contenuto da qualsiasi parte del codice.
|
|
|
|
|
Logged
|
Vi è una spiegazione scientifica a tutto. La fede è solo quell'anello che si porta al dito dopo il matrimonio.
|
|
|
|
0
Offline
Tesla Member
Karma: 87
Posts: 8493
:(){:|:&};:
|
 |
« Reply #4 on: February 27, 2013, 09:02:12 am » |
Terza cosa: il c++ tratta gli array come puntatori, quindi se crei un array variabile[3] lui ti crea un puntatore al primo elemento della lista. Per trovare un elemento della lista lui fa questa cosa: variabile[2] = *(variabile+2) A questo punto ti svelo un segreto del c++: variabile[2] = *(variabile+2) = *(2+variabile) = 2[variabile] E' un "baco" intrinseco del c++ per come tratta gli array...  non ho capito la storia del baco, puoi spiegare meglio? comuqnue che io sappia: variabile[2] = *(variabile+2*sizeof(tipoDell'array)) dove sizeof è la dimensione in byte della variabile float (4 byte nei sistemi 32bit, 8byte nei 64bit, ecco perchè inviare un float grezzo da arduino ad un PC 64bit può essere più problematico del previsto  ) importante perchè dando ad un array void non puoi usare [] (alcune implementazioni puoi e ti muovi di un byte), o puoi leggere un array di float byte per byte invece che float per float cambiando semplicemente il tipo di puntatore all'array... per spiegarmi: float n = 12.3; byte *p; p = &n; //ora P punta all'area di memoria di n for (int i=0; i<sizeof(float); i++){ Serial.print("byte: "); Serial.print(i); Serial.print(" = "); Serial.println(p[i], BIN); }
|
|
|
|
« Last Edit: February 27, 2013, 09:03:58 am by lesto »
|
Logged
|
|
|
|
|
Offline
God Member
Karma: 3
Posts: 602
"La teoria è quando si sa tutto ma non funziona niente. La pratica è quando funziona tutto ma non si sa il perché. In ogni caso si finisce sempre con il coniugare la teoria con la pratica: non funziona niente e non si sa il perché." Albert Einstein
|
 |
« Reply #5 on: February 27, 2013, 09:11:59 am » |
non ho capito la storia del baco, puoi spiegare meglio?
Prova a eseguire questo codice: int variabile[3] = {55, 46, 19};
void setup() { Serial.begin(9600); }
void loop() { Serial.println(variabile[1],DEC); Serial.println(1[variabile],DEC); delay(1000); }
EDIT Ho modificato il codice, diciamo che ero stato un po troppo precipitoso nello scriverlo... =)
|
|
|
|
« Last Edit: February 27, 2013, 09:17:33 am by Janos »
|
Logged
|
|
|
|
|
0
Offline
Tesla Member
Karma: 87
Posts: 8493
:(){:|:&};:
|
 |
« Reply #6 on: February 27, 2013, 09:36:01 am » |
Serial.println(variabile[1],DEC); Serial.println(1[variabile],DEC); ad occhio direi che dimostra che la chiamata sizeof() non viene fatta come dico io esplicitamente ma viene fatta all'interno dell'operatore +: indirizzo di variabile = 100 print1 = 100+1int (cioè 2 byte) = 102 print2 = 1int(cioè 2 byte) +100 = 102 con la sizeof esplicita: print1 = 100+ 1*sizeof(int)= 102 print2 = 1 +100*sizeof(int *) = 201 (tutti i puntatori sono di 2 byte!, ma in realtà fa una sizeof di variabile... se variabile è stato dicjhiarato come array, allora ritorna il numero dei suoi elementi (3 nel nostro caso), se invece è un puntatore all'array, oppure l'array è stato passato ricevuto come parametro (quindi in realtà è stato di nascosto trasformato in puntatore) ritorna sempre la dimensione dell'area di memoria del puntatore, che è 2byte (forse 4 nei 64bit) )
|
|
|
|
« Last Edit: February 27, 2013, 09:38:34 am by lesto »
|
Logged
|
|
|
|
|
ivrea (to)
Offline
God Member
Karma: 15
Posts: 912
|
 |
« Reply #7 on: February 27, 2013, 03:17:35 pm » |
Perchè non dovrebbe funzionare ? Arduino non è standard C++? byte On1, On2 On3; void loop() { funzione (On1,On2,On3); }
funzione (byte &p1, byte &p2, byte &p3) { } Questo è "Passaggio di parametri per riferimento" http://www.html.it/pag/15499/parametri-per-valore-o-per-riferimento/
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Tesla Member
Karma: 87
Posts: 8493
:(){:|:&};:
|
 |
« Reply #8 on: February 27, 2013, 04:55:53 pm » |
no, arduino usa il Wiring, che è in pratica C con un pizzico di C++.. e non conoscevo questa semplificazione del C++, c'è da vedere se arduino la supporta.
Quindi il primo sistema corretto è identico al terzo
|
|
|
|
|
Logged
|
|
|
|
|
Offline
God Member
Karma: 3
Posts: 602
"La teoria è quando si sa tutto ma non funziona niente. La pratica è quando funziona tutto ma non si sa il perché. In ogni caso si finisce sempre con il coniugare la teoria con la pratica: non funziona niente e non si sa il perché." Albert Einstein
|
 |
« Reply #9 on: February 28, 2013, 02:37:12 am » |
Wiring non è un linguaggio di programmazione, Arduino si programma in C++ al quale è stato aggiunto il framework Wiring, ovvero una serie di funzioni/librerie/API per semplificare la vita al programmatore. Wiring è un framework, non un linguaggio............ e non conoscevo questa semplificazione del C++, c'è da vedere se arduino la supporta.
A quale ti riferisci? A quella dell'esempio che ho postato io?
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Tesla Member
Karma: 87
Posts: 8493
:(){:|:&};:
|
 |
« Reply #10 on: February 28, 2013, 04:43:29 am » |
quella della & per ricevere puntatori al posto del * Arduino si programma in C++ Hai ragione ho controllato, la il punto è che è un C++ castrato, la prova è che negli IDE < 1.0 non esisteva nemmeno l'operatore new e delete.
|
|
|
|
|
Logged
|
|
|
|
|
Forum Moderator
Italy
Offline
Brattain Member
Karma: 226
Posts: 16988
Don't know what I do
|
 |
« Reply #11 on: February 28, 2013, 05:11:58 am » |
quella della & per ricevere puntatori al posto del * Arduino si programma in C++ Hai ragione ho controllato, la il punto è che è un C++ castrato, la prova è che negli IDE < 1.0 non esisteva nemmeno l'operatore new e delete. Questi sono stati introdotti nella versione 1.0.3, ne detti notizia io qualche settimana fa ricordi?
|
|
|
|
|
Logged
|
|
|
|
|
Rovereto
Offline
Jr. Member
Karma: 1
Posts: 80
|
 |
« Reply #12 on: February 28, 2013, 05:31:17 am » |
Ma quindi a parte l'errore che ho fatto di digitazione nella prima le 3 forme sono uguali? byte On1, On2 On3; void loop() { funzione (On1,On2,On3); }
funzione (byte &p1, byte &p2, byte &p3) { } Che io sappia questa forma è propria del C++ (non c'è nel C) come dice nid69ita ho provato ad utilizzarla e "sembra" funzionare... qualcuno però mi può confermare che funzioni come dovrebbe?
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Tesla Member
Karma: 87
Posts: 8493
:(){:|:&};:
|
 |
« Reply #13 on: February 28, 2013, 05:37:19 am » |
sì, non ricordavo la versione precisa ed ho generalizzato. Il punto è che bisogna fare mooolta attenzione a dire che è C++, io direi che è in pratica C con un pizzico di C++.. Ma quindi a parte l'errore che ho fatto di digitazione nella prima le 3 forme sono uguali? bhe la seconda usa un array che ha vantaggi e svantaggi ma in linea di massima sì, sono equivalenti Che io sappia questa forma è propria del C++ (non c'è nel C) come dice nid69ita esatto, se compila funziona, vai tranquillo
|
|
|
|
|
Logged
|
|
|
|
|
Offline
God Member
Karma: 3
Posts: 602
"La teoria è quando si sa tutto ma non funziona niente. La pratica è quando funziona tutto ma non si sa il perché. In ogni caso si finisce sempre con il coniugare la teoria con la pratica: non funziona niente e non si sa il perché." Albert Einstein
|
 |
« Reply #14 on: February 28, 2013, 05:40:56 am » |
Quello che hai fatto è passare alla funzione dei parametri come riferimento: http://www.html.it/pag/15499/parametri-per-valore-o-per-riferimento/Il che è tanto corretto quanto inutile. Come ti ho già detto sopra, quelle variabili sono definite globali e quindi visibili in tutto il programma. Se fai diventare il tuo codice così: byte On1, On2 On3; void loop() { funzione (); }
funzione () { } Funziona alla stessa maniera. Ti consiglio di dare un'occhiata a questo link, che fra l'altro spiega anche il tempo di vita delle stesse... http://webuser.unicas.it/tortorella/FondInf_0809/PDF/10-visibilita%20variabili.pdf
|
|
|
|
|
Logged
|
|
|
|
|
|