Newsgroup: it.hobby.elettronica.digitale
Titolo: Cast e qualificatori

Ciao,
capita di dichiarare array di caratteri come "volatile" (parlo di 
winavr) ad esempio se vengono popolati durante la ricezioni di caratteri 
nella ISR della seriale.
Può anche capitare di voler utilizzare delle funzioni come strlen o 
simili su tale array, le quali prevedono come parametro un const char *.
Il compilatore giustamente si lamenta:
Warning	1 (riferito all'utilizzo di strlen)	
passing argument 1 of 'strlen' discards qualifiers from pointer target type
Error	2 (riferito alla dichiarazione di strlen)
expected 'const char *' but argument is of type 'volatile char *'
E' giusto effettuare un "cast" (virgolette d'obbligo) del tipo:
if (strlen((const char *) line_buffer)) line_ready = TRUE;
Così il compilatore è contento, ma vorrei capire se è il modo giusto di 
procedere.
Grazie!
Marco

 if (strlen((const char *) line_buffer)) line_ready = TRUE;
Non vedo problemi, salvo il fatto che ovviamente la funzione chiamata (in
questo caso strlen) "non sa" che i dati puntati da line_buffer sono
volatile. Ciò che è veramente importante è che devi assicurarti che mentre
sei dentro a strlen() il contenuto dell'array non venga modificato dalla
ISR.
-- 
Fletto i muscoli e sono nel vuoto.

 ISR.
Intendi dire che se modifico i dati dell'array viene modificata anche la 
copia const passata strlen?
Quindi (const char *) cosa fa di preciso?
Grazie!
Marco

 Quindi (const char *) cosa fa di preciso?
Tu lo stai semplicemente usando per evitare le fastidiose lamentele del 
compilatore.  Fastidiose, ma utili.
IMHO (e nell'opinione del compilatore), un const char * � abbastanza 
diverso da un volatile char *.  La funzione strlen(), definita immagino 
in un altro file .c o addirittura in una libreria, vuole un const char * 
ed � stata compilata con questa assunzione, cio� il compilatore ha 
generato del codice che presuppone che i char dell'array non cambino 
improvvisamente.
Nel tuo caso, invece, i tuoi caratteri possono effettivamente cambiare 
in un interrupt e ci� potrebbe mandare in crisi la strlen(), in funzione 
di come � scritta e di cosa fa il compilatore.
Notare che ho scritto potrebbe... non � detto e solo una lettura del 
risultato della compilazione ti pu� garantire ci�.
In funzione di come � scritto il tuo algoritmo di ricezione dei dati da 
seriale nell'interrupt, potresti essere sicuro che, quando chiamo la 
strlen(), l'interrupt non ti fa cambiare quella parte di array.  In 
questo caso, anzich� utilizzare un cast che serve solo a nascondere 
avvisi importanti del compilatore, aggiungerei una funzione di helper, 
proprio per evidenziare la cosa.
   volatile char *buffer[BUFFER_LENGTH];
   size_t vstrlen (volatile char *s) {
     return strlen((const char *)s);
   }
Utilizzi sempre un cast, ma � localizzato in un unico punto.  In tutte 
le altre parti del codice userai la vstrlen().
Se poi non sei sicuro che quei caratteri non cambino, penso che la cosa 
migliore � copiare temporaneamente la stringa dall'array volatile in un 
array "normale".

 array "normale".
Che � quello che faccio normalmente nei codici pi� complessi. In questo 
caso era talmente banale da non richiedere la copia dell'intero array, 
semplicemente al termine della ricezione alzo un flag che mi impedisce 
ulteriori aggiornamenti dell'array sino al termine dell'elaborazione.
Ciao e grazie anche a te!
Marco

 utilizzo strlen i dati non vengono cambiati.
Scusa ma, se sei certo che quando ci accedi i dati non cambino, perch� 
hai dichiarato l'array volatile?
-- 
  _|/ Francesco Sacchi - Develer S.r.l., R&D dept.
   |\ 
http://www.develer.com/
 - 
http://www.bertos.org

 hai dichiarato l'array volatile?
Forse per paranoia :) Nel senso che io dichiaro come volatile le 
variabili modificabili dentro le ISR alle quali accedo nel resto del 
programma. Questo a prescindere dal fatto che mi possano cambiare 
*mentre* vi sto accedendo.
Faccio male? :-/
Marco


Beh, non esagerare :-)
Se sai che nel momento in cui ci accedi non cambieranno di sicuro, non 
c'� motivo di forzare il volatile.
Non che succeda nulla di particolarmente negativo, solo che in questo 
modo forzi il compilatore a rileggere il contenuto ogni volta, e questo 
ha degli effetti sulle performance.
Soprattutto se poi le usi all'interno delle ISR, anche l� dentro saranno 
trattate come volatile perch� il compilatore non sa che la ISR (in 
genere) non � interrompibile.


 genere) non � interrompibile.
In genere nelle ISR aggiorno i valori, mentre nel main loop le utilizzo 
(direttamente o facendone una copia in base al come gestisco gli accessi).
Ciao e grazie
Marco

 questo problema.
Esatto, ma nel caso della FAQ ti aspetti proprio che cambi :-)
Questo accade soprattutto con le variabili globali.
Nel tuo caso, hai un funzione che prende un puntatore a dei dati volatile.
E' chiaro che, essendo una funzione di libreria ed essendo un puntatore, 
i dati dovranno essere letti almeno una volta all'interno del corpo 
della funzione.
Ora, se sei sicuro che dal momento della chiamata e per tutta 
l'esecuzione della funzione l'array non cambier�, allora il volatile non 
� necessario, perch� se anche facesse un solo accesso (e uno almeno lo 
deve fare) puoi garantire che i dati non cambieranno e quindi tutto 
l'array sar� coerente.
-- 
  _|/ Francesco Sacchi - Develer S.r.l.
   |\ 
http://www.develer.com/
 - 
http://www.bertos.org/

 l'array sar� coerente.
Questo mi � chiaro.
Perdonami, ma quello che mi sfugge ancora �: senza dichiararla volatile 
posso comunque essere sicuro che quando vado a leggerla sto leggendo i 
valori attuali e non vecchi?
Marco

 valori attuali e non vecchi?
Certo, se chiami una funzione passando il puntatore ad un'area di 
memoria, la funzione chiamata sar� costretta per forza di cose a leggere 
i dati direttamente dal puntatore, e quindi avrai i dati attuali.
Come potrebbe fare altrimenti? Da dove prenderebbe quelli precedenti?
-- 


 Come potrebbe fare altrimenti? Da dove prenderebbe quelli precedenti?
Avevo ragionato da matematico, per induzione ;)
Partendo dall'esempio della FAQ dove veniva evidenziato il problema su 
un byte l'ho allargato a un intero array, dicendo che non � altro che 
una sequenza di byte.
Ma adesso ho capito che non si tratta di "dati vecchi" come avevo 
erroneamente assunto!!!!
Il numero di birre che ti devo offrire quando capiter� di incontrarci la 
prossima volta sta diventando notevole :)
Marco

 
Caro Marco i consigli proprio non fanno per te, ti e' difficile vendere la
frutta?

 bene la faccenda!
Di niente, alla prossima!
