Giocando con i vettori

Buongiorno a tutti.

Vorrei scrivere un “char” contenente l’output di un RTC. Nello specifico la formattazione desiderata è AAAAMMGG_HHMMSS (anno, mese, giorno, ecc…).

Leggendo in giro per il forum ho trovato una soluzione “compatta” che utilizza “sprintf”. Ho letto anche in altri post che tale funzione risulta essere “pesante”.

Ho messo insieme allora il codice alternativo sotto riportato, che funziona ma magari è anche peggiore di usare sprinf… E' così?

Volevo chiedere quali ottimizzazioni si possono apportare dal punto di vista formale / utilizzo delle risorse / utilizzo della memoria / ecc… più che altro per scopi didattici.

Grazie, G.

byte secondi;                                     
byte minuti;                                     
byte ore;                                         
byte giorno_mese;                                 
byte mese;  
char DataOra[16];
char temp[3];

   if (mese < 10){
     strcpy(DataOra, "20200");
   }else{
     strcpy(DataOra, "2020");
   }
   strcat(DataOra, itoa(mese, temp, 10));

   if (giorno_mese < 10) strcat(DataOra, "0");
   strcat(DataOra, itoa(giorno_mese, temp, 10));
   
   strcat(DataOra, "_");

   if (ore < 10) strcat(DataOra, "0"); 
   strcat(DataOra, itoa(ore, temp, 10));

   if (minuti < 10) strcat(DataOra, "0");
   strcat(DataOra, itoa(minuti, temp, 10));

   if (secondi < 10) strcat(DataOra, "0");
   strcat(DataOra, itoa(secondi, temp, 10));
   
 Serial.println(DataOra);

Potresti anche comporre due unsigned long: uno con l'orario e uno con la data:

unsigned long orario=10000*ore + 100*minuti + secondi;
unsigned long data=10000*anno + 100*mese + giorno;

poi trasformarli con itoa (accetta unsigned long?) e metterli insieme.

Ho provato, ma se non ho sbagliato qualcosa, è necessario definire come "unsigned long" anche tutte le variabili ore, minuti, secondi, ecc.... Queste però occupano 4 byte ciascuna anzichè 1 byte. O sbaglio?

Il codice come l'ho scritto io crea qualche "problema" con la memoria? Tipo quello che accade con "String"?

Ciao, G.

Per quanto riguarda le variabili:
ore e anno devono essere unsigned long;
minuti e mese devono essere unsigned int;
secondi e giorno devono essere byte.

In alternativa, con variabili byte tranne anno che, per 4 cifre, deve essere unsigned int:

unsigned long orario=ore; orario*=100;
orario+=minuti; orario*=100;
orario+=secondi;

unsigned long data=anno; data*=100;
data+=mese; data*=100;
data+=giorno;

JulianusGM:
Ho messo insieme allora il codice alternativo sotto riportato, che funziona ma magari è anche peggiore di usare sprinf… E' così?

A me il tuo codice sembra buono. Non vedo sprechi. Per la sprintf() dicono è pesante ma difficile dire quanto, non abbiamo i "sorgenti".
Puoi provare a fare una cosa. Uno sketch con sprintf() e uno con il tuo codice, vedi a fine compilazione quanto spazio memoria e spazio codice viene occupato che ti dice il compilatore e fai un confronto

Io avevo fatto a mano evitando la sprintf perchè in compilazione mi dava un uso di memoria maggiore e per formattare pochi dati, mi occupava meno fare la formattazione da mio codice custom che includere la sprintf.
Però, io stavo cercando modi per risparmiare memoria.
Se non sei a collo con la memoria puoi tranquillamente usare sprintf senza tanti patemi.

Maurizio

nid69ita:
... Per la sprintf() dicono è pesante ma difficile dire quanto, non abbiamo i "sorgenti".

... e pesante, è pesante ... la sprintf() di per sé non tanto, ma, in realtà, quella che chiama è la vfprintf() che è un bel mattone ::slight_smile:

Come è stato detto, dipende da quanta memoria resta libera ... se se ne ha, si può usare, altrimenti, meglio evitare :wink:

Guglielmo

x nid69ita, maubarzi, gpb01... grazie!

Allora mi sa che tengo il mio codice. Non sono "al limite" con la memoria, ma era per imparare a fare le cose "giuste", ossia imparare a risparmiare...

x Datman
Il tuo codice funziona utilizzando "ultoa" al posto di "itoa" (vedi sotto). Tra l'altro si risparmiano 100 byte di codice e 2 byte di memoria... vinci tu !! :slight_smile:

char temp[9];
   
   unsigned long orario = ore;
   orario *= 100;
   orario += minuti;
   orario *= 100;
   orario += secondi;

   unsigned long data = 2000 + anno;
   data *= 100;
   data += mese;
   data *= 100;
   data += giorno_mese;

   strcpy(DataOra, ultoa(data, temp, 10));
   strcat(DataOra, "_");
   strcat(DataOra, ultoa(orario, temp, 10));

   Serial.println(DataOra);

:slight_smile:

Cavoli...
mi sa che il tuo codice falla quando ore = 0 e in generale quanto ore < 10...
Vediamo se riesco a trovare una soluzione.

Beh... il codice che ti ho proposto fa solo calcoli matematici e produce un numero che sicuramente non può iniziare per '0' (o, se preferisci, inizia con tutti gli zeri che vuoi... :slight_smile: ). Devi aggiungere, quindi, qualcosa come

if(orario<100000) aggiungi in testa '0';
if(orario<10000) aggiungi in testa '0';
if(orario<1000) aggiungi in testa '0';
if(orario<100) aggiungi in testa '0';
if(orario<10) aggiungi in testa '0';

Questo, però, temo che sia inevitabile qualunque altra soluzione tu adotti!

Si, ok grazie.
Avevo cercato se c'era un modo per formattare i "numeri" anteponendo zeri, ma non trovo nulla. La tua soluzione sicuramente funziona.
Ciao.

Per formattarli con gli zeri iniziali devono diventare stringhe...

Prima fai ultoa(orario, temp, 10);
quindi con strlen(temp); sai quante cifre ha l'orario. da 6 a 1 carattere.
poi fai una strcat() di quanti zeri mancano e solo alla fine fai strcat(DataOra, temp);

ultoa(orario, temp, 10);
for(int i=0;i<6-strlen(temp);i++) strcat(DataOra,"0");
strcat(DataOra, temp);

Chiaro, chiaro.
Grazie.