Newsgroup: it.comp.lang.c
Titolo: sizeof e cast

Ciao,
ho un problema semplice ma mi perdo tra i vari cast e puntatori.
Date questa stringa e questa struct:
char user_jobdetail_location[16];
typedef struct {
	char  *name[2];
	int 	 type;
	void **data;
} menu_t;
di cui vediamo un esempio di inizializzazione:
const menu_t mn_jobdetail_location = {
	{"Location", "Luogo"},
	MIT_TEXTBOX,
	user_jobdetail_location
};
Vorrei recuperare la dimensione di user_jobdetail_location (altre
istanze della struttura potrebbero avere stringhe di dimensione
differente, ma comunque inizializzate a design-time).
Mi trovo ad avere il puntatore alla struttura e quindi a poter
accedere all'elemento data con
p->data.
Se voglio recuperare la stringa scrivo (char *) p->data, ma mi sfugge
come applicare l'operatore sizeof per sapere quanti byte è lungo
l'array puntato da p->data.
Grazie in anticipo!
Marco / iw2nzm

 l'array puntato da p->data.
L' operatore sizeof ottiene la dimensione dell'  operando dal suo tipo 
dati.  Non analizza la semantica dell'   operando. In parole povere 
otterrei solo la dimensione di un puntatore a puntatore a char.
Pero'  tu hai stringhe... strlen ?
Giorgio

 Pero'  tu hai stringhe... strlen ?
Eh no, troppo facile :)
Io non voglio sapere la lunghezza della stringa ma la massima lunghezza 
possibile, quindi la dimensione dell'array. Mi serve perché devo 
limitare i caratteri che si possono immettere e per ottimizzare le 
risorse (lavoro in ambiente embedded) vorrei definire per ogni stringa 
una lunghezza adeguata.
Ciao!
Marco / iw2nzm

 Scusa ma su queste cose ancora ci sbatto la testa :)
Tu hai un puntatore void**. Questo occupa quanto un normalissimo
puntatore: il compilatore non ha nessun modo per indovinare a runtime a
cosa punterà. Non è un array: è un puntatore.
-- 
-riko

 cosa punterà. Non è un array: è un puntatore.
Beh, non è esatto. Lo può sapere già in fase di compilazione perché la
struttura è istanziata come const e l'array è definito esplicitamente
quindi non è necessario essere a runtime per sapere a cosa punta.
Ad ogni modo, preso atto che non posso seguire questa strada, che
altra via mi suggerisci per recuperare tale dimensione?
Grazie ancora!
Marco / iw2nzm

 limitare i caratteri che si possono immettere  ...
Premesso che -come ti è stato detto- quello è un puntatore e che quindi a
runtime potrebbe puntare a qualsiasi cosa, se lo inizializzi con un
letterale stringa *NON* puoi utilizzare quello spazio per scriverci. I
letterali stringa sono array che per ragioni "storiche" possono decadere in
puntatore char* (non const), ma che NON sono comunque scrivibili. 
Se vuoi un area scrivibile puoi: 1. dichiarare un array, 2. allocare un
array con malloc.
Max

 quindi non è necessario essere a runtime per sapere a cosa punta.
No. Quando scrivi void **data; lui sa solo che hai un puntatore a
puntatore. Non sa *niente* altro. 
Se poi il tuo codice *in quel caso* lo inizializza, nulla impedisce che
in qualche altro punto cambi il valore del puntatore o quant'altro.
Resta comunque il fatto che non c'è scritto da nessuna parte dello
standard che il compilatore deve cercare di capire a cosa puntano i
puntatori.
Li hai scritto *esplicitamente* void** e lui quello sa. 
-- 
-riko

 array con malloc.
Nel caso 1 puoi anche poi inizializzarlo con una stringa.
No: char* foo = "foo";
Si: char foo[] = "foo";
--> char foo[4] = {'f', 'o', 'o', '\0'};
-- 
-riko

 Se vuoi un area scrivibile puoi: 1. dichiarare un array
Che è quello che ho fatto. Solo che ho bisogno di puntare a tale array
(mn_jobdetail_location) tramite il campo della struttura menu_t.
Questo perché ogni istanza della struttura punta ad array diversi.
Quindi riassumendo: posso leggere e scrivere tranquillamente il mio
array usando l'espressione:
(char *) p->data
dove p mi punta alla struttura di mio interesse.
Vorrei solo riuscire a sapere quanto grande è l'array puntato.
Ho capito che non posso fare come intendevo io, mi è chiaro. Ma quale
è la strada corretta?
Ciao!
Marco / iw2nzm

 in qualche altro punto cambi il valore del puntatore o quant'altro.
Il resto mi è chiaro, questo no: come è possibile che cambi il valore
del puntatore se la struttura è dichiarata const?
Ciao!
Marco / iw2nzm

 Non ho mai detto di averlo inizializzato con una letterale stringa!
Errore mio. Pensavo si stesse parlando di uno dei primi due campi.
Max

 sizeof(user_jobdetail_location).
Il "problema" è che avendo scarsità di risorse volevo minimizzare 
l'occupazione di memoria (flash in questo caso) visto che avrò molte 
decine di strutture istanziate.
A questo punto se non vi sono altri suggerimenti dovrò seguire questa 
strada.
Ciao!
Marco / iw2nzm

 del puntatore se la struttura è dichiarata const?
Quello che Enrico sta cercando di farti capire è che un puntatore e la
memoria a cui esso punta sono cose distinte. Il compilatore non fa
deduzioni in base a ciò che, presumibilmente o sicuramente (i.e. "const"),
sarà contenuto nella memoria puntata. Non puoi di certo aspettarti che
implementi un comportamento diverso di un operatore come sizeof in base a
ciò che sarà contenuto a run-time in quella porzione di memoria.
Il concetto è che, dato un puntatore, esso può puntare, di volta in volta,
a qualsiasi cosa, anche a zone di memoria di dimensioni diverse.
Che poi un puntatore costante non possa variare il suo riferimento è un
altro conto.
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

 altro conto.
mmm.... dovrei esserci :-)
Comunque per il problema in oggetto ho risolto grezzamente aggiungendo
un campo alla struttura. Già che stiamo facendo chiarezza ne
approfitto per domandarvi questa cosa.
Riprendiamo l'esempio di inizializzazione:
const menu_t mn_jobdetail_location = {
	{"Location", "Luogo"},
	MIT_TEXTBOX,
	user_jobdetail_location,  // <------------------
	sizeof(user_jobdetail_location)
};
Il compilatore (che tra parentesi è il Dynamic C per i moduli Rabbit)
si lamenta nel seguente modo sulla riga evidenziata:
WARNING: Type mismatch: incompatible types char[] and void * * const
used in expression.
WARNING: Conversion to incompatible pointer type
Premetto che il codice viene eseguito correttamente e fa quello che
deve. So anche i warning sono dovuti al fatto che sfruttando un
generico campo void ** ci metto dentro di tutto (stringhe, struct,
funzioni ecc...). La cosa è voluta in quanto mi evita di utilizzare un
campo per ogni tipo di dato.
Ma per fare le cose pulite c'è modo di evitare tali warning?
Marco / iw2nzm

Ma per fare le cose pulite c'è modo di evitare tali warning?
Per fare le cose pulite dovresti usare semplicemente un void* e non un
void**. Quello che accadrebbe, nel tuo caso, è che il nome dell'array
decadrebbe in puntatore al primo elemento, quindi char* e il char*
verrebbe convertito in void* automaticamente. In C, al contrario del
C++, per questo tipo di up-cast non c'è bisogno di cast esplicito.
Le cose funzionano comunque, nel tuo caso specifico, perché alla fine
un void** è comunque un puntatore, della stessa dimensione di un char*
e quindi non ci sono problemi. 
Voglio sottolineare una cosa: attenzione a dire, in generale, "il
codice funziona correttamente". In generale, lo stesso codice potrebbe
avere molti comportamenti corretti per un lungo periodo e poi, un bel
giorno, per una strana congiunzione astrale, manifestare bug grandi
come crateri lunari. Bisogna fare molta attenzione ai warning perché
quasi sempre sono sintomo di guai seri, annidati subdolamente. E - non
mi stancherò mai di ripeterlo - fate i test, fate i test, f-a-t-e i
t-e-s-t.

 t-e-s-t.
Più che altro per la mia (poca) esperienza non è tanto la quantità di 
test a "garantire" un programma privo di bug ma la loro qualità e varietà.
Ciao e grazie per la pazienza!
Marco / iw2nzm

 tipo di dato compresi i puntatori a funzione?
Non è garantito. (void *) puo' contenere qualunque puntatore ai dati ma 
non necessariamente puntatori a funzione.
Se ho capito bene stai scrivendo codice embedded, giusto? Quindi a 
maggior ragione dovresti verificare bene il manuale del compilatore.
Remo D.

tipo di dato compresi i puntatori a funzione?
No, i puntatori a funzione sono un caso a parte.

Non è garantito. 
Infatti: undefined behavior.

 void**. 
Da quello che ho capito del suo problema, forse potrebbe usare una
union. Usare un puntatore generico e poi "metterci dentro cose diverse"
è tipicamente un caso in cui ci potrebbe stare una union, IMHO.
-- 
-riko

 di cui non ne capisco i vantaggi e quindi divento acido con me stesso :)
Il vantaggio č tenere il linguaggio piccolo e semplice. Poi ci sono
anche "errori storici". Che so... a livello di libreria ci sono funzioni
che "sarebbe meglio che non ci fossero". Qualcuno ha detto gets? O
magari che i default fossero girati (IMHO le versioni "piů facilmente
accessibili" dovrebbero essere quelle che controllano la lunghezza
dell'output, strncpy e non strcpy etc etc etc). Ma ormai č tardi.
Per il resto C deve essere efficiente e efficientemente implementabile
su un numero spropositato di piattaforme. E quando č nato per certi
versi era pure peggio. E amen.
-- 
-riko

versi era pure peggio. E amen.
Il punto infatti è: più comode per chi? :-)
Con il C sono state fatte scelte prevalentemente dettate dalle
prestazioni. E' vero che in Delphi (non so se funzioni ugualmente in
FP) le stringhe possono tenere a mente la propria lunghezza in una
porzione di memoria antecedente il contenuto vero e proprio, ma è
anche vero che implementano molti altri meccanismi, come il
reference-counting e il copy-on-write, che in C introdurrebbero
problemi prestazionali...

 è tipicamente un caso in cui ci potrebbe stare una union, IMHO.
Ci ho provato a usare le union e mi sono scontrato con un'altra 
"limitazione". Ok non prendetevela :)
Posso solo inizializzare il primo campo e non un altro. Quindi sono 
inusabili per quello che mi serve. Oppure dovrei inizializzarle a 
run-time ma in questo caso perdo il vantaggio di limitare l'occupazione 
di ram.
/* mode ottuso on */
Questo è un altro caso di cui non capisco il vantaggio: sappiamo che 
posso leggere da una union il campo precedentemente scritto. Bene, ma 
perché non posso *inizializzare* uno qualunque dei campi? Quale motivo 
ha spinto gli sviluppatori a limitare l'inizializzazione al primo?
/* mode ottuso off */
Tornando al mio puntatore generico: il perché di questo campo flessibile 
è presto detto. Ho scritto un semplice codice che mi permette di 
implementare un menu utente interattivo (tipo quello di qualsiasi tv o 
vcr di oggi) dove mi basta inizializzare le strutture e automagicamente 
posso gestire inserimenti testuali, comandi, parametri multipli, check 
box ecc...
Non sarà il massimo dell'eleganza però mi ha risolto un problema che 
altrimenti non avrei saputo affrontare (tenendo conto delle limitazioni 
di risorse).
Quindi per concludere la discussione, per fare quello che sto facendo 
devo tenermi i warning, giusto?
Ciao!
Marco / iw2nzm

 devo tenermi i warning, giusto?
No.
-- 
-riko

 union foo f = { .d = 4 };
Peccato che il mio compilatore non sia C99... Come ben saprai sono molto 
rari i compilatori C99 per microcontrollori. Tu mi dirai "e allora cosa 
pretendi?" beh, fino al C99 vuol dire che c'erano validi motivi per 
impedire questa inizializzazione....
Ciao!
Marco / iw2nzm

 wrote in
news:g9qs7k$c6k$
1...@tdi.cu.mi.it
: 

union foo
{
    	char c[2];
    	int  i; //int -> 16 bit
};
union foo f;
f.i = 4;
"perdi" una cella di memoria (2byte in proc a 16bit) per
l'inizializzazione, ma di ram non perdi nulla. 
magari si puo' fare:
union foo
{
    	char c[2];
    	int  i = 4; //int -> 16 bit
} f;
ma non sono sicurissimo e non ho voglia di provare.
Ciao Jack
PS: giusto per:
union foo
{
    	char c[2];
    	int  i; //int -> 16 bit
};
e
union foo
{
    	int  i; //int -> 16 bit
    	char c[2];
};
sono equivalenti.
-- 
Eroi non si nasce, ti incastrano
- Jim Belushi

 sono equivalenti.
Giusto, ma non posso dichiarare n strutture diverse per ogni tipo che 
voglio inizializzare :)
Ciao!
Marco / iw2nzm

 impedire questa inizializzazione....
Ho visto spesso fare la cosa con questa sintassi:
union foo { int i; double d; };
union foo f = {d:4};
È *sicuramente* un'estensione del GCC. Non ho idea (non ho lo standard
C89) se fosse parte dello standard precedente. 
Puoi comunque spulciare il manuale del tuo compilatore per capire che
cosa supporti. IMHO la probabilità che *non* esista nessuna estensione
per fare quello che vuoi è piuttosto bassina. 
Poi per le variabili automatiche (o le strutture allocate dinamicamente)
inizializzarlo immediatamente dopo è probabile che venga gestito
dall'ottimizzatore. 
-- 
-riko

 decine di strutture istanziate.
La soluzione che hai adottato minimizza l'occupazione di memoria. Delle 
due l'una:
- o ti calcoli le lunghezze delle stringhe in runtime;
- oppure le memorizzi come costanti.
Non mi pare ci possano essere alternative.
E.