Buongiorno a tutti.
Vado a descrivere l'esigenza cosi da circoscrivere l'ambito della richiesta:
capita spesso che per i nostri progetti abbiamo bisogno di variabili "personali" tipo token oppure di variabili che consentono di "configurare" un dispositivo (dover ricompilare un firmware per aggiornare questo tipo di informazioni lo trovo una cosa inaccettabile!) o variabili che vogliamo salvare in modo permanente.
Vorrei aggiungere una funzionalità ad una delle mie librerie per facilitare la gestione agli utenti meno smaliziati delle situazioni di questo tipo, ovvero offrire la possibilità di salvare e caricare un set di variabili NON omogenee usando un semplice metodo generico tipo loadValues() e saveValues()
La libreria in questione è pensata per i dispositivi Espressif e consente di salvare e recuperare queste variabili dalla memoria flash usando un file di configurazione in formato JSON (al momento però questo aspetto è di secondaria importanza ed il discorso può essere esteso ad altre MCU e/o sistemi di memorizzazione).
Pensandoci un po' su mi è venuta quindi questa idea:
usare il polimorfismo delle funzioni per determinare il tipo delle variabili
crare una linked list di struct (ma poteva essere anche un semplice array) dove vado a salvare il puntatore alla variabile (come void*), il tipo della variabile e una chiave che la identifica in modo univoco nella lista.
usare uno switch/case sul tipo di variabile per forzare il casting al tipo di dati necessario quando si deve leggere/scrivere il valore della variabile
Il tutto funziona correttamente come si può vedere e simulare in questo esempio wokwi, ma se devo essere sincero non è che mi piaccia poi tanto... lo trovo troppo "laborioso".
Considerazioni?
Qualche idea per ottenere la stessa cosa in modo più smart?
@Standardoil sono finalmente riuscito a dare uno sguardo alle tue funzioni.
Non mi è proprio tutto chiaro, ma di base penso di aver capito i ragionamenti che hai fatto.
Per inizializzare le variabili partendo dal file "/file.ini" mi pare di capire che usi la macro che hai definito all'inizio che prevede come parametro in ingresso la variabile, giusto?
Questo però presuppone che si debba fare una chiamata per ciascuna variabile in modo tale che il compilatore possa risolvere il tipo da inserire poi nel template per ciascuna chiamata specifica.
Purtroppo non è esattamente ciò che vorrei realizzare.
Io vorrei aggiungere un ulteriore spolverata di zucchero a velo (se possibile):
L'utilizzatore della libreria stabilisce quali sono le variabili che vanno nel file di configurazione e le aggiunge alla lista;
L'utilizzatore della libreria chiama la funzione bool caricaVariabili(void) all'inizio dell'esecuzione o quando necessario;
L'utilizzatore della libreria chiama la funzione bool scriviVariabili(void) quando è necessario salvare.
A runtime o a compiletime?
Perché temo che a runtime non sia possibile
Avevo pensato anch'io un salvataggio e un restore "monolitici", di tutto quello che serve
Ma così perdevo in flessibilità, che invece cercavo
Nulla vieta, a partire da operazioni singole, definire azioni "aggregate"
Viceversa invece è più complesso
Una strada che avevo esplorato e poi lasciato cadere era quella di "concentrare" tutte le variabili da salvare e ricaricare in un'unica struttura e poi movimentare solo quella
Ma ho lasciato stare, troppo monolitica, il file corrispondente non sarebbe stato facilmente editabile su PC
Il problema poi è sempre che a runtime non si ha accesso ai nomi delle variabili, quindi decidere al volo cosa salvare o ricaricare diventa difficile
Infatti questo è lo scoglio più alto da superare ragione per cui al puntatore della variabile ho associato un'etichetta che la rappresenta e purtroppo anche io temo che altre soluzioni a run-time non siano possibili.
Ora in questo caso l'etichetta era già disponibile perché usata per generare la pagina web di configurazione in modo dinamico, ma volendo avrei anche potuto ricavarla dal nome stesso della variabile usando il pre-processore di "stringification" #
Quello che mi piacerebbe fare a questo punto è eliminare il meccanismo dello switch/case, però non ho proprio idea di come fare a risalire al tipo di variabile partendo solo dal suo indirizzo (ovviamente solo a compile time, ammesso che sia possibile)
Pure io avevo tentato di passare per lo overload di funzioni per ottenere in return un "indice" del tipo di variabile
Ma non funzionerebbe per tipi non nativi
A runtime è una bella sfida
A compiletime è tutto più semplice, ma meno flessibile
Avevo anche pensato di salvare la variabile in modo "brutale" copiarla byte per byte, magari codificando base64
In questa maniera non ti serve di conoscerne il tipo, ma solo la dimensione
E funzionerebbe anche per tipi non primitivi
Ma non puoi editare il file ottenuto