Go Down

Topic: Creare Librerie (Read 21207 times) previous topic - next topic

Maurotec

@lesto
Puoi impedire alla funzione di modificare una variabile passata per riferimento o alias tramite il qualificatore  "const", stessa cosa per il passaggio di una variabile puntatore. Questo però l'ho già scritto nei post precedenti. 8)

Ciao.


mastraa

Il libro della O'Reilly lo sto aprendo ora che ho un computer disponibile e lo guardo!

Grazie Mauro, mi hai chiarito diversi aspetti, provo a riassumere per vedere se ci sono:

&var ricava l'indirizzo della variabile
io posso dichiarare *pointer (ferma restando la compatibilità tra tipi di variabili)
a questo punto posso assegnare a pointer l'indirizzo di var: pointer=&var
e quindi leggere var anche per mezzo di *pointer.

Nelle funzioni, nei parametri da passare:

'chiedere' &value permette di utilizzare value come se fosse la mia variabile che passo, quindi modificando value modifico anche la mia variabile. Però non posso leggerla perché ne ho solo l'indirizzo, se non tramite il 'giochetto' di prima passando per un puntatore.
Se ho necessita di leggere e modificare la richiedo tramite *value?

Maurotec

#47
Mar 25, 2014, 03:28 pm Last Edit: Mar 25, 2014, 03:41 pm by MauroTec Reason: 1
Quote

'chiedere' &value permette di utilizzare value come se fosse la mia variabile che passo, quindi modificando value modifico anche la mia variabile. Però non posso leggerla perché ne ho solo l'indirizzo, se non tramite il 'giochetto' di prima passando per un puntatore.
Se ho necessita di leggere e modificare la richiedo tramite *value?


Non è chiaro, fai un esempio di codice, così evitiamo fraintendimenti.
Il termine 'chiedere' &value, non è comprensibile.

Vuoi potere accedere ad una variabile da dentro una funzione nello stesso modo in cui la usi da fuori la funzione, ma senza usare puntatori? Nella lista di parametri della funzione usa & prima del nome della variabile, da dentro la funzione la userai nel modo consueto. Questo ovviamente modifica la variabile, in quanto non viene fatta copia locale come per il passaggio per valore.

ops ho dimenticato di chiarire una cosa.

Nella dichiarazione della funzione, i parametri sono da considerarsi essi stessi una dichiarazione, per cui
int &myAlias è una dichiarazione, che potrebbe anche essere detta in questi termini:
hei tu C myAlias è un argomento da passare per riferimento, capito!!
Mentre quando ricavi l'indirizzo di una variabile tramite &, l'indirizzo deve essere ricavato a tempo di esecuzione, qua la cosa si complica un pò a causa della allocazione dinamica della memoria, comunque il compilatore se conosce l'indirizzo di una variabile durante la compilazione risolve in modo statico, diversamente ricava il valore a tempo di esecuzione, cioè durante l'esecuzione del programma.

Ciao.

mastraa

Vorrei capire la differenza tra le due funzioni, nel senso che entrambe vanno a modificare la variabile che io passo nella posizione di value(s).

Dopodichè in alcuni esempi (anche nei link che mi sono stati postati prima) vedo che quando ha l'* poi nel richiamarla devo usare & (ma qui ad esempio non lo fa, la seconda ad un certo punto richiama la prima).

Rimango 'ingannato' dal fatto che l'esito sembra lo stesso, ma sicuramente c'è un motivo perché si usa uno o l'altro modo.

Code: [Select]
char SFE_BMP180::readBytes(unsigned char *values, char length)
// Read an array of bytes from device
// values: external array to hold data. Put starting register in values[0].
// length: number of bytes to read
{
char x;

Wire.beginTransmission(BMP180_ADDR);
Wire.write(values[0]);
_error = Wire.endTransmission();
if (_error == 0)
{
Wire.requestFrom(BMP180_ADDR,length);
while(Wire.available() != length) ; // wait until bytes are ready
for(x=0;x<length;x++)
{
values[x] = Wire.read();
}
return(1);
}
return(0);
}

char SFE_BMP180::readUInt(char address, unsigned int &value)
// Read an unsigned integer (two bytes) from device
// address: register to start reading (plus subsequent register)
// value: external variable to store data (function modifies value)
{
unsigned char data[2];

data[0] = address;
if (readBytes(data,2))
{
value = (((unsigned int)data[0]<<8)|(unsigned int)data[1]);
return(1);
}
value = 0;
return(0);
}

lestofante

#49
Mar 25, 2014, 05:34 pm Last Edit: Mar 25, 2014, 06:08 pm by lesto Reason: 1
quando hai un puntatore, allora devi passre un undirizzo. Una cosa strana sono gli array; essi infatti sono dei puntatori sotto mentite spoglie! quindi NON hanno necessità di mettere lo & davanti, anzi, se usi il nome dell'array con il * è come fare
Code: [Select]
[0] (leggi il primo elemento).

Devi studiare bene quelle guide, i puntatori non si imparano dall'oggi al domani, ti mancano puntaori a funzioni, puntatori doppi (e così via), puntatori void, puntatori a strutture, liste dinamiche, e un intero mondo.
Guida per principianti http://playground.arduino.cc/Italiano/newbie
Unoffical Telegram group https://t.me/genuino

Maurotec

@lock
Anche in asm puoi usare una cella di memoria al cui interno ci scrivi un indirizzo di memoria, che equivale a creare puntatori, ma in quel caso ricavi il contenuto della prima cella e lo usi per accedere alla cella di memoria che risiede a quell'indirizzo. Quindi non credo che si tratti di C, C++ o pascal o modula ecc, semplicemente la ram è fatta così. Ma poi che mi fai scrivere che lo sai meglio di me  :smiley-yell:

Quote
Rimango 'ingannato' dal fatto che l'esito sembra lo stesso, ma sicuramente c'è un motivo perché si usa uno o l'altro modo.


Nella tua testa c'è una grande confusione, che diminuirà solo dopo che sperimenti in prima persona come funzionano il C/C++, e l'unico modo è quello di usare un compilatore per PC o (IDE). Crei alcune variabili e stampi i loro indirizzo, crei funzioni e passi i parametri in tutti i modi conosciuti, nessuna variante esclusa. Sperimentare con il C/C++ su un dispositivo embedded non è pratico nè comodo, se ti convinci di ciò ti renderai conto come stanno le cose e alla fine considererai anche banale l'argomento che comunque non mancherà di fregarti quando meno te lo aspetti.

readBytes prende un puntatore ad tipo unsigned char, quindi il puntatore sarà grande 16 bit ma la cella a cui punta è grande 8 bit. Nella chiamata puoi passare un puntatore o un array (vedi cosa dice lesto).

Nel caso specifico di readBytes la funzione è pensata per gestire l'array passatogli attraverso il puntatore "values", infatti il parametro seguente si chiama length, cioè lunghezza di che ? dell'array.

readUInt prende due argomenti, il primo passato per valore e il secondo passato per riferimento.

Se vuoi puoi scrivere dei pezzi di programma piccoli a cui aggiungi i commenti (chiari chiari) che poi noi qui li correggiamo.

char *charPtr; // Un puntatore non ha segno quindi unsigned char al posto di char, ma non è un obbligo
charPtr prende 2 celle di memoria in quanto il puntatore in AVR è grande 16 bit.
Il dato a cui punta invece è grande 8 bit (lo specifica char).
Per ricavare il dato (valore) a cui punta charPtr si antepone *, es: char myChar = *charPtr; // ricavo il valore e lo salvo in myChar, il valore può avere segno negativo o positivo.

charPtr++; incrementa il puntatore di 1 cella, questo mi da accesso alla cella seguente charPtr.
*(charPtr++) incremento e ricavo il valore.

Sono un poco maligno perché voglio che ti convinci a sperimentare il C/C++ su un pc, sarò ancora più maligno
(se prima non lo fa lesto) la prossima volta con i puntatori a puntatori (che mi procurano mal di testa). 

Ciao.

lestofante

#51
Mar 26, 2014, 11:58 am Last Edit: Mar 26, 2014, 12:06 pm by lesto Reason: 1
@lock: guarda, a ta punto potrei salvarti un saccod i mal di testa con codesto programma, che interpreta il codice in modo matematico e becca tutti gli undefined behaviur

https://code.google.com/p/c-semantics/

edit: ah occhio che si sono spostati su https://github.com/kframework/c-semantics
Guida per principianti http://playground.arduino.cc/Italiano/newbie
Unoffical Telegram group https://t.me/genuino

mastraa

Torno a sfruttare questo topic con un'altra domanda per la libreria che finalmente ho trovato il tempo di scrivere!

Sono arrivato al punto in cui ho bisogno di sfruttare una libreria trovata in giro dentro la mia. Mi spiego, devo usare la libreria OneWire (le sue funzioni) all'interno della mia classe DS18B20. So che esiste già la DallasTemperature, ma per questioni di spazio e velocità ho bisogno di crearmi la mia versione.

Ora ho letto che si può fare qualcosa del tipo class DS18B20: public OneWire, ma non trovo degli esempi con cui capire bene la sintassi e come funziona la cosa.

Qualcuno mi può aiutare?

mastraa

Ho capito il mio problema, ma non ho capito come risolverlo (sempre che sia una cosa ammessa in C):

per dichiarare una classe derivata di un'altra è sufficiente scrivere

class miaClasseDerivata: public miaClassePrincipale {...}

il mio problema deriva qualora miaClassePrincipale richiedesse dei parametri nel costruttore (come appunto OneWire)

leo72

A parte che stiamo parlando di C++ e non di C, non sono ferratissimo sull'argomento ma credo che tu abbia sbagliato qualcosa nel tuo codice (che non fornisci per cui vado ad intuito).
Leggi prima qui:
http://www.learncpp.com/cpp-tutorial/114-constructors-and-initialization-of-derived-classes/


mastraa

alla fine sono riuscito a risolvere grazie anche all'aiuto di un amico più esperto. In pratica in tutti i tutoria che avevo trovato facevano sempre esempi di classi in cui il costruttore non richiedeva parametri. In tal caso (benché consigliato) non è obbligatorio richiamare il costruttore della principale dentro a quello della derivata. Cosa che invece è necessaria avendo costruttori che richiedono parametri nella classe principale (come appunto OneWire).


mastraa

Torno nuovamente a porre una questione, sto lavorando con la solita libreria e ora mi viene un errore che non capisco, ho già affrontato diverse volte la classe derivata da un altra, ma ora mi da un errore che non capisco.

Code: [Select]
class LCD_CLASSIC: public LiquidCrystal
{//riga 133!!!
public:
    LCD_CLASSIC(byte rs, byte enable, byte d4, byte d5, byte d6, byte d7);
    void start();
private:
    byte _col;
    byte _row;
};


Questo è il codice che ho scritto e mi dice che:

Code: [Select]


In file included from MPU6050.ino:4:
/Users/mastraa/Documents/Arduino/libraries/Mille/Mille_UNO.h:134: error: expected class-name before '{' token


alla riga 4 inserisco la mia libreria.
dentro la libreria ho incluso LiquidCrystal.h così come ho fatto per la Wire.h e anche la LiquidCrystal_I2C.h...

dove sbaglio?

leo72

Pare che ti sia scordato una parentesi.
Allega tutto il codice che usi (file .h, file .cpp e file .ino).

mastraa

Era una cosa ancora più stupida, forse non devo più mettermi alle 23 a fare ste robe!

Semplicemente avevo incluso LiquidCrystal dappertutto, meno che nello sketch di Arduino  :smiley-roll-sweat:

PS: ma il problema ancora più grosso è che mi sono sbagliato stanotte con la soluzione  :smiley-eek:

lestofante

se estendila classe onewire è perchè vuoi aggiungerene/modificarne le funzionalità. se vuoi solo usarla allora la usi e basta come fai conla Serial (che però è statica) o la Servo.

se apri la libreria DSblabla vedrai che è una semplice classe che USA la OneWire per fare quello che vuoi fare tu: quindi la libreria stessa che vuoi sostituire è la tua base di partenza!
Guida per principianti http://playground.arduino.cc/Italiano/newbie
Unoffical Telegram group https://t.me/genuino

Go Up