Salve,
sono abbastanza alle prime armi con il c++ e mi sto scontrando con un problema di risoluzione del nome di una funzione in una classe. Ho scritto un codice per fare una serie di menu su LCD gerstiti da un encoder. per fare questo ho scritto una classe myMenu ( forse non molto ottimizzata ) con costruttore e metodi che funziona bene. purtroppo essendo i menù tanti l'occupazione della RAM è considerevole e alla fine arrivo a saturarla. Pensando di liberarla pensavo di utiliz zare la funzione pgm_read_word ( per salvare in flash tutte le stringhe costanti della classe ) che però mi funziona solo nello spazio globale.
In pratica ho questa situazione:
In pratica sia che io metta o non metta l'operatore di di risoluzione dell'ambito :: al momento della compilazione ottengo sempre lerrore :
error: '::myLcdPrint' was not declared in this scope ::myLcdPrint ( dum_c) ;
L'errore si presenta sia che io usi come IDE platformio sia che usi arduino IDE 2.1.0
Sono fermo e non riesco a capire dove sto sbagliando .......
Oltretutto è l'unico errore di tutto il codice che è abbastanza articolato.....
Sarò molto grato per qualsiasi aiuto potrete darmi .......
Ci ho messo un po per capire, anche se la richiesta è semplice il codice che hai postato mi ha disorientato. Ancora non sono sicuro, ma il codice che hai postato è parziale giusto?
Prova a inserire questa riga nel file myMenu.cpp:
extern void myLcdPrint( int8_t index);
PS: non mi piace proprio, non l'ho mai visto fare in C++ una cosa simile, cioè si trattasse di una sola funzione potresti documentarla per metterla in risalto.
Riguardo a extern leggi a seguire sul perché è necessario:
Ti ringrazio per la sollecota risposta e confermo che il codice è parziale.
Ho provato il tuo suggerimento ma purtroppo non cambia le cose ....
E' come se l'operatore risolutore di Ambito :: non funzionasse o come se quando il compilatore arriva a generare il file obj di myMenu.cpp non avesse traccia dello spazio globale del file.ino.
Ho provato allora a mettere nel file myMenu.h la seguente dichiarazione extern void myLcdPrint( int8_t);
e provando a compilare sia con i :: che senza ottengo un nuovo tipo di errore :
error: storage class specified for 'myLcdPrint' extern void myLcdPrint( int8_t);
oppure
error: '::myLcdPrint' has not been declared ::myLcdPrint ( dum_c) ;
è un mistero ....
Mi interessa capire perchè non è possibile scrivere un codice come quello postato perchè ,tra l'altro, apparentemente contraddice quello che ho letto nei manuali di c++ e quello che risponde ChatGPT alla stessa domanda. Per il programma , se non trovo una soluzione, cerchero di trasformare tutti i
cpa2Lcd -> print ( MENU.. [] );
// in
cpa2Lcd -> print ( F( "......." ));
// dove il vettore carattere MENU..[] è sostituito nel sorgente con la stringa di origine "......"
Rimane sempre il dubbio sul perchè non funziona l'operatore ::
Ti ringrazio in ogni caso per la risposta.....
Ciao
Non saprei a me funziona, ha sempre funzionato, ci sarà qualcosa che sbagli, prova a creare uno sketch minimale e postalo così possiamo capire da dove deriva quell'errore.
Provato ora ora e funziona e so anche perché funziona, ma non so come mai non funziona a te. Funziona sia con :: che senza.
Ti ringrazio,
Ho provato la tua soluzione ed è perfettamente funzionante. In pratica rispetto a quello che avevo scritto io ci sono solo due differenze:
La prima è che nel file cpp la definizione "extern void externfunction () " è prima del costruttore
La seconda è che vel file .h la definizione della funzione myMethod è pubblica e non privata.
Utilizzando questa semplice funzione ricavata dal forum
extern int __bss_end ;
extern void *__brkval ;
int memoryFree ()
{
int freeValue ;
if ((int) __brkval == 0 ){ freeValue = ((int)&freeValue) - ((int)&__bss_end) ;}
else {freeValue = ((int)&freeValue) - ((int)__brkval ) ;}
return freeValue ;
}
ho potuto verificare che dopo l'inizializzazione del programma ( creati tutti gli oggetti ) la RAM libera è passata da 192 bytes a 1434 bytes. Così dovrei riuscire a completare il progetto.
Mi sapresti spiegare perchè parrebbe così importante la posizione della definizione extern nel file cpp ?
Grazie ancora per avermi risolto il problema
Ciao
Nel file usi una funzione che il compilatore non è in grado di risolvere.
Aggiungendo le righe
extern int __bss_end ;
extern void *__brkval ;
stai definendo due prototipi di funzione e quindi queste due funzioni le puoi usare nel tuo metodo.
Allo stesso momento dici al compilatore che il codice di quelle funzioni si troverà su un file esterno al tuo .cpp
A quel punto il linker è in grado di mettere insieme tutti i pezzi e produrre il firmware compilato correttamente.
Se per fare un test aggiungi un prototipo di funzione extern, ma poi non lo definisci da nessuna parte, potrai osservare che il compilatore non ti da errori, ma il linker non è in grado di generare il file binario correttamente.
Se deve essere private: non puoi certo chiamare il metodo da istanza di classe, ma puoi solo chiamarlo da metodi interni alla classe. In ogni caso extern risolve la visibilità del simbolo. Ma attenzione che l'uso smodato di extern non è pratica comune ed è sconsigliato in tutti i manuali. In sostanza extern fa male al programmatore che prima o poi non ci capisce più nulla.
Potrai quindi usare il simbolo lcd per come sei abituato, sia dentro una funzione che dentro un metodo di classe.
Dipende tu dove l'hai scritta, in genere basta scriverla prima di usare il simbolo extern, certo che se lo metti dopo non ha molto senso, stessa cosa inserirlo a caso.
PS: Riguardo a chatGPT et company, perdi solo tempo, l'unico valido motivo per usarli e se ti pagano per allenarle a me non mi pagano e mi sono scocciato di correggerle sempre.
Hai ovviamente ragione,
Del fatto che non potesse essere private me ne ero già accorto ma l'errore che facevo era di inserire l'istruzione con "extern .... " dopo il metodo che la doveva usare. Posizinandola il testa al cpp o almeno prima del metodo che la usa funziona. Ti ringrazio per avermi sottolineato questa particolarità del compilatore a cui non avevo prestato sufficiente attenzione.
Per quanto riguara l'uso di extend concordo con te sull'uso smodato. In effetti è la prima volta che la uso perchè preferisco usare le classi con relative chiamate per puntatore. Nelle classi, poi, cerco di definire pubblici il minor numero di metodi e varabili possibile.
Per quanto riguarda ChatGPT , hai anche quì ragione da vendere. La sto provando per curiosità ma , a parte esempi molto semplici , da risposte molto spesso sbagliate.....
Grazie, sembra banale ma ha richiesto molto impegno onde evitare di creare un blog copia privo di contenuti come quelli che trovi in testa alla SERP.
Una precisazione è sempre dovuta riguardo al significato dei termini definire e dichiarare che negli ultimo decennio molti considerano sinonimi. Ho dichiarato guerra contro la disinformazione ma ancora non ho definito come combatterò, come quali armi e quanto è grande il mio esercito. Possiamo dire che una dichiarazione è una definizione povera, carente di dettagli, ma è una forzatura.