Newsgroup: it.hobby.elettronica.digitale
Titolo: puntatore ad una costante

ciao!
come noto alcune architetture non permettono puntatori ad una costante;
sono su un pic18 adesso con compilatore ccs v4
per aggirare questo ostacolo di solito faccio:
char s[10];
s="123";
lcd_write(s, 3);
il prototipo ï¿œ lcd_write(char s[], int len);
se faccio lcd_write(s="123", 3) compila ma non va bene
perchï¿œ?
-ice-

 -ice-
Effettivamente ho appena provato ed è come dici; se ti metti con il
simulatore e fai lcd_write(s="345", 3) vedrai che il valore in s[]
viene aggiornato a"345" ma purtroppo viene passato il puntatore nullo
e non quello di s[] , provare per credere (io voto per un bug)
Ciao!
.

 perch�?
Probabilmente � un bug, comunque se la stringa che devi scrivere � una 
costante, potresti definirla come:
#define   s   "123"
cos� che viene allocata in rom ma funziona (almeno quando usavo CCS 
funzionava se ricordo bene)
Se scrivi:
for (i = 0; i < sizeof(s); i++) {
   if (s[i] == 0x00) break;    //per il carattere di fine stringa
   lcd_gotoxy(coordinate dove vuoi scrivere);
   lcd_putc(s[i];
}
cosa succede?
Ciao
CG 

 perch ?
lcd_write("123", 3) non funziona?

 lcd_write(s, 3);
s="1234" e' sbagliato. 
Come minimo, strcpy(s, "1234");

 Come minimo, strcpy(s, "1234");
non ï¿œ sbagliato... magari non ti viene aggiunto il \0 (che a me non 
serve dato che passo giï¿œ la lunghezza)
-ice-

 lcd_write("123", 3) non funziona?
no... ï¿œ quello di cui stiamo parlando;
se fai come hai scritto non compila perchï¿œ non ï¿œ possibile creare un 
puntatore ad una costate
-ice-

 cosa succede?
non ho ancora provato ma suppongo che sizeof(s) restituisca la 
dimensione del puntatore ad s... quindi non va
-ice-

 e non quello di s[] , provare per credere (io voto per un bug)
anch'io propendo per un bug...
-ice-

 del puntatore ad s... quindi non va
puoi anche usare strlen, che ti evita la prima riga del ciclo. Con MikroC 
funziona.
Ciao
CG 

 funzionava se ricordo bene)
Manco per niente. il #define � un'istruzione al preprocessore, che, per
definizione, non alloca nulla da nessuna parte. Infatti la caratteristica
fondamentale degli header file (.h) dovrebbe essere di non allocare nulla,
ovvero contenere solo prototipi e istruzioni pel preprocessore.
La dichiarazione che alloca esplicitamente in ROM �, con Codevision
flash char pippo[] = "1234";
Che, per inciso, alloca 5 byte.

 serve dato che passo gi� la lunghezza)
Anche i PIC hanno architettura harward, ovvero con dati e programma
separati, o no?
Con il tuo compilatore, una funzione che accetta come parametro un
puntatore a RAM non � diversa da una che accetta un puntatore a ROM?
Il tuo compilatore non te lo segnala?

 lcd_write(s, 3);
Cosa succede se fai:
lcd_write((char*)"123", 3);
?
-- 
emboliaschizoide.splinder.com

 ha scritto:

Come fai tu e' sbagliato (giusto per la cronaca, gcc non lo compila).
E' corretto (ma bruttino, imho):
  char stringa[10]="123";
Il terminatore se usi i doppi apici non serve. Potrsti anche scrivere:
  char stringa[10]={'1','2','3','\0'};
in questo caso si deve mettere il terminatore.
In ogni caso, niente ï¿œ meglio di:
  const char stringa_costante[]="1234";
  printf("%s",stringa_costante);

 -ice-
Perche' non puoi assegnare una stringa ad un array cosi'.
Invece :
lcd_write("123",strlen("123"));
Dovrebbe funzionare.
Se vuoi una stringa costante, dovresti fare cosi':
const char* s="123";  // Puntatore a una stringa
Oppure:
const char s[]={'1','2','3',0x0}; // array
e quindi:
lcd_write(s,strlen(s));

 }
S� ma se sai gi� la dimensione della stringa (con strlen, non con 
sizeof) chettefrega cercare il carattere di fine stringa? :-)
Tra l'altro gotoxy lo metterei fuori dal ciclo...
P.

 Il tuo compilatore non te lo segnala?
Uhm...
(*) S�, lo so. E me ne vergogno. :-(

 perchï¿œ?
Dipende da cosa restituisce l'assegnazione (un puntatore in ram?)... Non 
puoi controllare l'assembler che ti genera?
P.

 (*) S�, lo so. E me ne vergogno. :-(
Penitenziagite!
Detto fra noi, non conosco per nulla il PIC18, potrebbero aver finalmente
copiato qualcosa dagli AVR...

 Ma poi: che senso ha chiedere la lunghezza della stringa? 
Pu� essere utile nel caso tu debba estrarre un messaggio da un buffer.
Io talvolta lo faccio. Chiaramente, se il parametro lunghezza � zero, si
utilizza la stringa fino al primo '\0'.

 copiato qualcosa dagli AVR...
Niente di pi� facile. L'architettura in s� (e la scelta di periferiche) 
non mi sembra cos� male. Il problema sono i bachi nel silicio dei quali 
loro negano sfacciatamente l'esistenza. Per non parlare dell'MCC18 che 
fa acqua da tutte le parti (vabb�, io son fermo alla versione 2.4, ma 
dubito che le cose siano cambiate radicalmente). Sono quasi certo che le 
librerie standard e soprattutto quelle di gestione delle periferiche le 
ha scritte uno studente di liceo (o mentalmente equivalente), la met� 
delle quali semplicemente non funziona, tanto che ad un certo punto ho 
smesso di usarle.
Prossimo progetto ARM tutta la vita anche se dovesse servirmi per far 
lampeggiare un LED.


Io in quei casi me lo "riscrivo". Ovviamente � una questione di numero 
di volte che hai bisogno di fare l'una e l'altra cosa (visualizzare 
stringa/parte di stringa), ma in generale il rapporto 
beneficio/rottura_di_maroni � abbastanza basso. Mi sembra abbastanza 
inutile aggiungere un parametro se poi il 99% delle volte questo � zero: 
tanto vale scriversi due funzioni (o due stringhe in questo caso).
Ma sono punti di vista ovviamente.

 sono su un pic18 adesso con compilatore ccs v4
non ci credo;  il pic18 puo' accedere a costanti in flash almeno in 3
modi diversi, uno dei quali utilizza un apposito puntatore.
saluti
-- 
  lowcost

 modi diversi, uno dei quali utilizza un apposito puntatore.
http://it.tinypic.com/r/zlrlgm/6
-ice-

 Il tuo compilatore non te lo segnala?
dal forum ccs leggo questo;
credo sai proprio il limite che incontro io
"The key is that the PIC, has a Hoffman memory architecture, with 
separate memory 'spaces' for the code memory, and the variable memory. 
Now on the older PICs, the code memory is not even accessible for data 
storage by the program, so if you define a 'constant' string, it is 
implemented as a program to return the data, rather than as addressable 
storage locations, and cannot be directly accessed. CCS, elected on this 
basis, to have no provision to access this memory, and 'pointers' only 
access the variable memory. Latter chips do allow the memory to be 
accessed, but as yet the old restriction remains in place for CCS code."
-ice-


il pic18 lo puo' fare:  cambia compilatore o fallo in assembler.
saluti
-- 
  lowcost

 Ma sono punti di vista ovviamente.
Il punto di vista importante � quello del compilatore.
Con certe ottimizzazioni potrebbe farti due funzioni che, stabilito il
numero di caratteri da elaborare, chiamano una subroutine che effettua
l'elaborazione. Insomma, ottieni un codice un po' pi� lungo con una CALL e
un RET in pi�. Pi� chiss� quanti registri pushati/poppati.

 Il punto di vista importante � quello del compilatore.
C'hai raggione anche tu, ma io mi riferivo in particolare all'MCC18 :-p
Esso colui il quale non sa la (non) differenza tra un ciclo da 0 a 10 e 
uno da 10 a 0 (il secondo viene compilato con la met� delle istruzioni).

 ha scritto nel messaggio 
news:hkc93e$g7q$1...@speranza.aioe.org...

qui per� non � colpa del compilatore ma delle istruzioni a basso livello che 
ha a disposizione....
In parecchi microcontrollori esiste l'istruzione di decremento con 
comparazione con lo zero (in ambiente pic decfsz), quindi se imposti il 
contatore e poi lo decrementi con poche istruzioni ottieni lo scopo.
Viceversa, impostare a zero un contatore, incrementarlo per poi compararlo 
'a mano' di volta in volta con il valore da raggiungere, comporta circa il 
doppio delle istruzioni. 

 comporta circa il doppio delle istruzioni.
Non lo metto in dubbio. Non sono un esperto di compilatori ma immagino 
non sia difficile verificare se il contatore venga effettivamente usato 
nel ciclo e almeno nel caso questo non avvenga trasformare un ciclo 
crescente in uno decrescente a 0, ti pare?
P.

 in uno decrescente a 0, ti pare?
Non penso sia cos� semplice.
Il contatore � in una zona di memoria, nulla vieta che un programma 
(scritto, male, ma questo il compilatore non pu� saperlo...) vada a leggere 
il contenuto della memoria utilizzando degli spiazzamenti calcolati ed un 
indirizzamento indiretto (es se il contatore � un array o se � contenuto in 
una struttura).
Quindi io lancio il ciclo di conteggio e con un'altro processo vado ad 
utilizzare la stessa locazione di memoria della variabile per altri scopi 
(es. la coordinata per rappresentarne il valore su schermo).
Quindi se faccio un riferimento diretto alla locazione di memoria, il 
compilatore si pu� accorgere delle mie 'intenzioni'.
Se viceversa faccio un accesso indiretto, potrebbero emergere fastidiosi 
problemi.... 

 problemi....
Di nuovo, ti chiederei un esempio di accesso indiretto senza usare il 
nome dato al contatore.
P.

 nome dato al contatore.
Come vedi la differenza tra linguaggi ad alto e basso livello che ho
esposto sopra ha implicazioni notevoli.

 esposto sopra ha implicazioni notevoli.
S�, ma a favore della mia tesi :-p
P.

 S�, ma a favore della mia tesi :-p
La tua tesi di rompicoglioni a grati? ;-)
No. Punto.

 L'implementazione � per� totalmente diversa.
Sipper�, sipper�. La sintassi � uguale? S�. Punto.
� possibile determinare (i.e. processando un file di testo) se la 
stringa "i" viene usata da qualche altra parte che non sia nel ciclo for?
S�?
OK.
No?
Motivare la propria risposta con un esempio illustrativo.

 Motivare la propria risposta con un esempio illustrativo.
L'ho gi� fatto. Se quella i � la variabile del tuo loop, ce l'hai in un
piede.

 Pongo subito rimedio: char i = 3; char* p =&   i; char* q = p; *q = 4;
Che me stai a cojona'?
Sar� meno furbo del compilatore ma per me la i � ancora l�...
Per chiudere quello che qualcuno potrebbe obiettare essere un flame, non 
ho mai scritto un compilatore (n� ho intenzione di farlo in questa vita 
e neanche nella prossima). Dico solo che secondo me in linea di 
principio � possibile fare ci� che dico. Siccome mi ritengo 
(immodestamente) una persona modesta, non ho nessuna pretesa che ci� che 
sostengo io abbia una qualsivoglia implicazione sul come stanno 
realmente le cose. Dico solo che secondo me si pu� fare. Almeno finch� 
tu o qualcun altro mi convincete del contrario con un esempio.
Oppure, visto che non vuoi rispondermi tu, mi rispondo da solo:
char i
char *p=&p--
for (i=1; i<=10; i++){
   (*p)++;
}
Ammesso che i e p vengano allocate consecutivamente... Ma questa � una 
porcheria immonda e senza senso ed � giusto e doveroso che il programma 
esploda senza piet� in seguito alla "mia" ottimizzazione :-p
Per la cronaca, nel caso non fosse chiaro, l'ottimizzazione consiste in:
for (i=10; i>0; i--){
   (*p)++;             //Ripristina il decremento del contatore
}                     // e non esce mai

 e neanche nella prossima).
Allora non fare un master in CS. Ti fanno due cojoni cos� insegnandoti e
facendoti fare cose utili solo in questi frangenti.

 facendoti fare cose utili solo in questi frangenti.
Tranquillo, ne ho abbastanza di quello che sto facendo... Appena finisco 
(se mai) vado direttamente a coltivar patate.

 Tra l'altro gotoxy lo metterei fuori dal ciclo...
sizeof l'ho messo perch� se ho gi� allocato s[] da qualche parte so quant'� 
lungo, e posso ciclare fino a che non trovo un null del fine stringa. strlen 
consuma molta pi� ram e rom
per il gotoxy ti d� piena ragione ;)
Ciao
CG 

 ovvero contenere solo prototipi e istruzioni pel preprocessore.
infatti la stringa non viene allocata al momento della define, ma viene 
sostituita dentro alla funzione, e poi allocata in ram o rom a seconda del 
prototipo della funzione stessa:
const char *   -> rom
char * -> ram
Ciao
CG 

 per il gotoxy ti d� piena ragione ;)
:-)
Ciao!
P.

 facendoti fare cose utili solo in questi frangenti.
CS sarebbe?
-ice-

 CS sarebbe?
Computer Science.

 (se mai) vado direttamente a coltivar patate.
La patata ha sempre il suo bel perch�.

 Credo, dovrei controllare, che ce ne sia uno per la ram ed uno per la rom.
Il codice che ho scritto io in effetti non � troppo bello 
programmaticamente, dove se viene fatta una funzione per calcolare la 
lunghezza di una stringa andrebbe usata sempre quella, per coerenza. Il 
vizio per� di stare sempre entro la dimensione del vettore, qualsiasi cosa 
succede, a volte salva da problemi runtime di violazione di accesso 
difficilmente individuabili visto che quasi mai nei firmware, almeno quelli 
pi� piccoli e tipici, gira un sistema operativo. A mio parere il codice pi� 
corretto sarebbe quindi questo:
lcd_gotoxy(coordinate dove vuoi scrivere);
lcd_WriteString( (const char *) s);
dove:
void lcd_WriteString (const char * string) {
    unsigned int i;
    for (i = 0; i < sizeof(string) && i < strlen(string); i++) {
       if (string[i] == 0x00) break;    //per il carattere di fine stringa
       lcd_putc(string[i]);
    }
}
oppure forse occupa meno:
void lcd_WriteString (const char * string) {
    unsigned int i = 0;
    do {
         if (string[i] == 0x00) break;    //per il carattere di fine stringa
         lcd_putc(string[i++]);
    } while(i < sizeof(string) && i < strlen(string));
}
ciao
CG 

 
Entrambe queste funzioni non funzionano ;-)
L'operatore sizeof(), applicato su un const char *, ti ritorna la 
dimensione del puntatore.
Il sizeof ritorna la dimensione dell'array solo se, appunto, l'oggetto ï¿œ 
un array dichiarato staticamente.
-- 
  _|/ Francesco Sacchi - Develer S.r.l., R&D dept.
   |\ 
http://www.develer.com/
 - 
http://www.bertos.org/

 un array dichiarato staticamente.
Appunto. In origine, e credo in tutte le implementazioni per
microcontroller, viene calcolato durante la compilazione.

F. Bertolazzi ha scritto:

A quanto ne so io viene calcolato sempre a compile time, su qualunque 
architettura, perch� � appunto un operatore (unario) e non una chiamata 
a funzione come potrebbe sembrare.


 a funzione come potrebbe sembrare.
L'avrei detto anch'io (non quella dell'operatore, visto che l'essere
operatore non comporta la valutazione durante la compilazione, anzi), ma,
prima di scrivere, mi sono documentato. Il C99 prevede anche che sizeof
ritorni anche la dimensione di array la cui dimensione viene specificata a
run-time.
Una stupidaggine, secondo me, ma, si sa, quando c'� di mezzo un comitato
non sempre � la ragione a vincere, ma il carattere del pi� prepotente.

 non sempre � la ragione a vincere, ma il carattere del pi� prepotente.
Beh, in ogni caso i compilatori non sono stupidi, useranno la versione 
dinamica solo quando serve. E poi di compilatori C99 compliant ce ne 
sono davvero pochi, come hai detto tu mi aspetto che quelli per embedded 
sostituiscano sempre il sizeof con una costante a compile time.


 un array dichiarato staticamente.
l'ho usato pi� volte con successo su array costanti dichiarati nella forma:
const char string[] = "stringa";
sizeof ritorna 8
strlen ritorna 8
per fare ste prove al volo ho utilizzato mikroC per pic
Ciao
CG 

 const char string[] = "stringa";
Che, infatti, non � un char*. Non � una variabile, neppure una lvalue.
Il compilatore, quando trova il simbolo "string", lo sostituisce con un
puntatore al primo carattere dell'array.

 strlen ritorna 8
Come ti ha giï¿œ risposto il Bertolazzi, funziona perchï¿œ in questo caso 
sono array dichiarati staticamente.
Nelle funzioni che hai postato, invece, la stringa viene passata come 
parametro ed esse prendono un const char *, che ï¿œ diverso da un const 
char [].
Prova a fare questo:
const char string[] = "stringa";
const char *str = string;
e a stampare:
strlen(stringa)
sizeof(stringa)
strlen(str)
sizeof(str)
Vedrai che l'ultimo sizeof(str) ti ritorna 2 (o 4 se i puntatori sono a 
32bit).
