Go Down

Topic: Ottimizzare la gestione delle stringhe (Read 10543 times) previous topic - next topic

overmike

Sto realizzando una sorta di terminale o forse è meglio dire un pannello di controllo con la classica configurazione:
Arduino Uno + LCD 20x4 + keypad 4x4 + lettore SD.
Tale pannello lo uso per monitorare/comandare una seconda unità remota dedicata alla domotica (tutto fatto in casa).
Arrivo alla domanda e/o consiglio.
Arduino riceve dall'unita' remota via seriale una serie di comandi composti da 4 byte
Esempio: "#RST" - "#CNP" - "#CNC" ecc.
Per interpretare in modo veloce il tipo di comando avevo pensato a questa soluzione:

Code: [Select]
  string ListaComandi = "#RST#CNP#CNC#SET"
  string carRx = "#CNP"          // stringa in arrivo dalla seriale

  int Posizione = ListaComandi.indexOf(carRx);

  switch (Posizione) {
    case 0:
           // comando #RST
      break;
    case 4:
           // comando #CNP
      break;
  }


E' possibile ottimizzare tale codice?

gpb01

#1
Feb 25, 2014, 10:25 pm Last Edit: Feb 25, 2014, 10:27 pm by gpb01 Reason: 1
Certo che è possibile, cambiandolo proprio ...  :smiley-mr-green: :smiley-mr-green: :smiley-mr-green:

Premesso che hai sbagliato a scrivere, visto che il C è sensibile alle maiuscole ed alle minuscole .... la classe che vuoi usare tu è "String" e non "string" (... che, in realtà è un char array) ... io comunque sconsiglio sempre l'uso di detta classe su una MCU piccola come quella di Arduino che ha solo 2 KBytes di SRAM.

Ricorda che le String vengono allocate dinamicamente in memoria usando la malloc() e, ogni volta che ne cambi la loro lunghezza, vengono distrutte e riallocate !
Dato che non c'è un "garbage-collector" ... in breve tempo ti ritrovi con la memoria frammentata ed inutilizzabile, con conseguente blocco/perdita di controllo del programma.

La strada che io consiglio e invece quela di usare le stringhe del C, ovvero i char array null terminated (... ovvero, per indicare la fine di una stringa, si mette un byte a 0x00) e le funzioni della AVR libc per manipolarle, in particolare, quelle presenti in <string.h>.

Se guardi bene ce ne sono per tutti i gusti, comprese quelle per cercare un certo insieme di caratteri all'intero di una stringa e tornare l'indice di dove si è trovato ... strstr() ;)

Gli strumenti per ottimizzare ora li hai ... vedi un po' come utilizzarli ...

Guglielmo

P.S. : Quelle funzioni sono altamente ottimizzate. Ho provato a sostituirle scrivendole io con cicli di for ... ma ... con pessimi risultati  :smiley-mr-green: :smiley-mr-green: :smiley-mr-green:
Search is Your friend ... or I am Your enemy !

nid69ita

#2
Feb 25, 2014, 10:59 pm Last Edit: Feb 26, 2014, 11:00 am by nid69ita Reason: 1
@overmike, aggiungo: si l'algoritmo che hai pensato è ottimo, lo uso spesso.  Soprattutto in VB e linguaggi ad alto livello.
Ma, come ti dice @Guglielmo, gli oggetti String sono pesanti. Puoi applicare lo stesso algoritmo ma con l'uso di stringhe (vettori di caratteri terminati da null ovvero carattere '\0') usando i vari comandi strncmp() oppure strstr()

Poi  se Posizione lo dividi per 4 (nel tuo caso, la lunghezza del singolo comando) ottieni un valore progressivo 0,1,2.. invece di 0,4,8... meno semplice da gestire.
Puoi anche rendere più leggibile il codice usando delle costanti o degli enum:
Code: [Select]
#define K_CMD_RST 0
#define K_CMD_CNP 1
...
if(Posizione>=0) Posizione=Posizione/4;
switch (Posizione)
{ case K_CMD_RST:
....
 case K_CMD_CNP:
...
my name is IGOR, not AIGOR

overmike

Ok!
Mi si è aperto un nuovo mondo e io che pensavo di aver già imparato qualcosa.
Adesso e' tutto da rifare, almeno nell'approccio al "C"!
Vedrò di studiarci sopra.

Grazie di tutto!

Renzo

gpb01

Ahahahah ... no, dai, non è tutto da rifare ... devi rivedere alcune cose, il concetto di base che volevi seguire resta :)

Guglielmo
Search is Your friend ... or I am Your enemy !

overmike

Arrivo da una discreta esperienza di Assembler e dopo vari passaggi sono arrivato a VB6, ma rimanendo affezionato al primo.
Con l'assembler puoi far di tutto, ma devi anche preoccuparti di tutto, con VB invece avevi un strada ben definita, ma non dovevi preoccuparti di niente (o quasi).

Qui con Arduino mi sembra di trovarmi a metà strada.
Quando affermi (e ti credo) "in breve tempo ti ritrovi con la memoria frammentata ed inutilizzabile...."
è qualcosa che non digerisco da un sistema che dovrebbe in certo qual modo guidarmi o bloccare certe scelte!

Va be'', scusa dello sfogo vedro' di darmi da fare

Renzo

nid69ita

#6
Feb 26, 2014, 03:17 pm Last Edit: Feb 26, 2014, 03:20 pm by nid69ita Reason: 1

Arrivo da una discreta esperienza di Assembler...


Scusami, ma non sono d'accordo. Anzi provieni dall'assembly. Arduino si programma in C/C++ e il C è stato sviluppato proprio per sostituire l'assembly, perciò rimane un linguaggio orientato più verso il basso livello.
Inoltre stai lavorando su un microcontrollore (MCU), pensato come attuatore di circuiti elettronici, non ad un microprocessore su PC con sistema operativo e montagna di Ram.
Secondo me il VB6 ti ha "viziato"  ;)
Almeno io la vedo così.   :D
my name is IGOR, not AIGOR

gpb01


...
Quando affermi (e ti credo) "in breve tempo ti ritrovi con la memoria frammentata ed inutilizzabile...."
è qualcosa che non digerisco da un sistema che dovrebbe in certo qual modo guidarmi o bloccare certe scelte!


Dimentichi che stai su una MCU (... non su un computer) e non c'è il sistema operativo ...
... il sistema operativo sei tu ...  e sei tu che decidi cosa fare e quali rischi correre.

Il C ti mette a disposizione tutto (... quasi come l'assembler) e come funzionano malloc(), dealloc() e realloc() è piuttosto chiaro.
Chiunque le usi (... sia esplicitamente, sia implicitamente usando una classe che ne fa uso) ... deve sapere a cosa va incontro ... non c'è nessuno al di sopra a controllare  XD

Guglielmo
Search is Your friend ... or I am Your enemy !

overmike

Confesso che sono alla mia prima esperienza in assoluto con il "C" con le ovvie conseguenze del caso.

Cio' nonostante mi sento autorizzato a criticare il fatto che se un sistema di sviluppo e/o un linguaggio mette a disposizione una serie di funzionalità, risulti ragionevole pensare di poterle utilizzare senza alcuna riserva. Magari faranno perdere in efficienza la CPU, ma lontano dai miei pensieri sospettare che il loro uso possa compromettere la stabilità del sistema.

Mi sono riletto la documentazione delle varie funzioni stringa, e in nessun caso è stato riportato "attenzione all'uso delle funzioni stringa perche' puo creare instabilita".

Non dimenticate che sono stati proprio i vs consigli, che reputo comuque affidabili, a farmi cambiare rotta sullo sviluppo del mio software. 

Renzo

p.s.
A tutt'oggi, lavoro ancora in assembler con un mitico Z80 con 32K di ram, mentre da poco ho abbandonato le MCU  della serie ST6 che mettevano a disposizione 3000 byte per il codice e poco meno di 128 byte di RAM, e posso assicurarvi che gli ho fatto fare miracoli.




gpb01

#9
Feb 26, 2014, 10:10 pm Last Edit: Feb 26, 2014, 10:13 pm by gpb01 Reason: 1
Mah ... vedi il problema è che Arduino è per la "diffusione alla massa" ... e alla "massa" non puoi fargli sbattere la faccia su cose complesse, perché altrimenti ci rinuncia in partenza.

Questa cosa ha portato a tutta una serie di scelte che, se viste con gli occhi di chi ha esperienza, sono senz'altro discutibili (... basti pensare solo ai problemi che crea aver nascosto agli utenti main.c , i prototipi delle funzioni, ecc. ecc. ... tutte cose nascoste dal IDE), ma viste da parte della "massa" sono enormi semplificazioni e ... tutto ciò ha un prezzo ...

In realtà, su MCU così piccole è un suicidio usare il C++ (... e ricorda che tu dici C, ma i problemi derivano non dal C, ma dall'uso del C++ perché String in C non esiste) ... ma la cosa ... ha enormemente semplificato la vita alle "masse" che ... se le limitavi al solo ANSII C ... avrebbero incontrato moltissime difficoltà a capire ... ed avrebbero abbandonato !

Purtroppo ... "avere la botte piena e la moglie ubriaca" non è possibile ... ;)

Vuoi evitare problemi ... programma, come faccio io, in ANSI C ...  :smiley-mr-green:

Guglielmo

P.S. : Tu considera che l'altro giorno, un utente, pur di non mettersi "a capire" come ricevere dei caratteri sulla seriale e ricostruire una stringa ... ha preferito usare la Serial.readBytesUntil(), che gli nasconde tutto quello che c'è dietro. Tutto per evitare di dedicare del tempo a studiare ...   :smiley-roll:
Search is Your friend ... or I am Your enemy !

leo72


Cio' nonostante mi sento autorizzato a criticare il fatto che se un sistema di sviluppo e/o un linguaggio mette a disposizione una serie di funzionalità, risulti ragionevole pensare di poterle utilizzare senza alcuna riserva. Magari faranno perdere in efficienza la CPU, ma lontano dai miei pensieri sospettare che il loro uso possa compromettere la stabilità del sistema.

Nessuno ti toglie il diritto alla critica, ma devi comunque capire che anche su un computer Pentium con 128 MB di memoria non puoi farci girare un sistema operativo come Windows 8 o Linux/KDE  ;)
Ogni cosa ha i suoi limiti. 2K di RAM sono 2K di RAM, comunque tu li voglia girare. Se hai bisogno di maggior "spazio" ci sono altri prodotti, o la DUE oppure altre MCU a 32 bit di ultima generazione che offrono clock e risorse molto superiori a quelle offerte dall?Atmega328.

PS:
anch'io ho programmato in assembly, tanti anni fa, e capisco che con l'assembly spremi fino all'ultima goccia le risorse di una macchina, ma un linguaggio di più alto livello è quasi indispensabile se non vuoi diventare matto ad usare tutte le periferiche o se devi interfacciarti con HW esterno. Quindi qualche rinuncia o compromesso devi metterli in conto.

gpb01

@ Leo : Su una cosa però overmike ha ragione ...


Mi sono riletto la documentazione delle varie funzioni stringa, e in nessun caso è stato riportato "attenzione all'uso delle funzioni stringa perche' puo creare instabilita". 


... se tu puoi segnalare la cosa ... magari nella descrizione di "String" ... una nota che indica di stare attenti all'uso della memoria che fa questa classe ... ci starebbe bene ;)

Guglielmo
Search is Your friend ... or I am Your enemy !

leo72

Questo è vero, sentirò se si può inserire una postilla nella pagina:

PS:
però non c'è neanche scritto da nessuna parte che non puoi creare un array di int con 2000 elementi  ;). Bisogna avere un minimo di conoscenza di quello che si ha sottomano (non è rivolto a te, ci mancherebbe  :smiley-sweat:)


gpb01


... però non c'è neanche scritto da nessuna parte che non puoi creare un array di int con 2000 elementi  ;)


Credo siano due cose differenti, anche se ... essendo il prodotto un prodotto di "massa" ... una serie di piccoli "warning" qua e la, nella documentazione, non avrebbero certo fatto male ...  ]:D

Però una cosa è ovviamente non tenere conto dei limiti di ciò che si ha, un altra è usare un qualche cosa convinti di stare nei limiti che però, per il suo funzionamento intrinseco, provoca problemi (... es. una String di una dimensione ragionevole a cui però cambi la dimensione N volte) ;)

Guglielmo
Search is Your friend ... or I am Your enemy !

overmike

Ok!
Comunque alla fine ci siamo capiti sui discorsi!

Io pero adesso mi do una letta alla string.h e vedo cosa posso tirarne fuori e poi
se ho bisogno mi faccio vivo perchè conto sul vs aiuto.

Renzo

Go Up