Newsgroup: it.comp.lang.c
Titolo: sapere a cosa punta un puntatore

*** post for FREE via your newsreader at 
post.newsfeeds.com
 ***
avete presente l'operatore istanceOf di java?
Esiste qualcosa di simile in C?
Io ho un gpointer (che dovrebbe essere un void*) che mira ad una
struttura da me
prima dichiarata. Il problema è che a priori non so che struttura è e
siccome ho
definito più strutture completamente diverse io devo essere in grado
sapere che
struttura è per castare il gpointer correttamente altrimenti mi trovo
una valanga
di errori di puntatori a variabili che non esistono.
Come posso fare?
Ciao e grazie
-- 
Non c'è più forza nella normalità, c'è solo monotonia.
-----= Posted via Newsfeeds.Com, Uncensored Usenet News =-----
http://www.newsfeeds.com
 - The #1 Newsgroup Service in the World!
-----==  Over 90,000 Newsgroups - 16 Different Servers! =-----

 cut
Ciao Ottavio,
potresti aggiungere un campo alle tue strutture in cui specifichi un codice
per la tua struttura, cosicche´ il tuo puntatore puo´ sicuramente riferirsi
a quel campo visto che sicuramente esiste in tutte le strutture a cui punta,
per adattarsi alle azioni da farsi.
Ora pero´, visto che ogni struttura avra´ dei campi diversi, non trovo altre
soluzioni che un bel switch - case per gestire le azioni da farsi che
ovviamente varieranno da struttura a struttura.
Ma penso che ci siano soluzioni migliori dello switch-case che e´ la piu´
banale.
Forse con un array di puntatori a funzione, con ogni puntatore che abbia
l´indirizzo della funzione che gestisca l´azione corrispondente alla
struttura scelta?
Forse se fai un esempio concreto dell´uso che stai facendo di questo
puntatore sarebbe meglio.
Maurus

 di errori di puntatori a variabili che non esistono.
puoi usare una seconda variabile che ti dice come interpretare il gpointer.
se, per esempio, stai scrivendo una funzione che utilizza il gpointer:
enum gptype { TYPE1,TYPE2,...,TYPEN };
void fun ( enum gptype type, void * ptr )
{
  switch( type )
  {
  case TYPE1:
  {
    struct type1 * p=ptr;
    p.campo = ...;
    ...
  }
  case TYPE2:
  {
    struct type2 * p=ptr;
    p.field = ...;
    ...
  }
  ..
  case TYPEN:
  {
    struct typeN * p=ptr;
    p.champ = ...;
    ...
  }
  }
}
per questo tipo di cose, al posto dei pointer void*, puoi usare le union, ti
evitano cast e pointer di appoggio aggiuntivi:
union data
{
    struct type1 type1;
    struct type2 type2;
    ...
    struct typeN typeN;
};
void fun ( enum gptype type, union data * ptr )
{
  switch( type )
  {
  case TYPE1:
    ptr->type1.campo = ...;
    break;
  case TYPE2:
    ptr->type2.field = ...;
    break;
  ...
  case TYPEN:
    ptr->typeN.champ = ...;
    break;
  }
}
ciao
donCiccio

 banale.
Il problema nasce dal fatto che nella libreria gtk il puntatore data
associato ad una riga in una clist è un gpointer per poter puntare a
qualsiasi cosa. Il problema è che come dati associati ad una riga non ho
un solo tipo di dato....
lo switch-case mi va benissimo, però ho un dubbio...
considera:
typedef struct {
	char *nome;
	char *cognome;
	int numero_struttura = 1;
} prima_struttura;
typedef struct {
	int numero_telefono;
	int numero_struttura = 2;
} seconda_struttura;
a parte la banalità dei campi che ho messo le due strutture non hanno la
stessa dimensione e soprattutto non hanno la variabile numero_struttura
con lo stesso offset dentro la struttura.
Posso fare lo stesso il giochino di chiamare gpointer->numero-struttura
? O rischio che sbagli a puntare indirizzo?
Nel secondo caso, ammesso che io metta il numero di struttura come prima
variabile, sono sicuro o no che il compilatore me lo metta poi come
primo campo effettivo? O rischio che per problemi di allineamento il
compilatore (gcc) mi sposti l'ordine delle variabili nella struttura?
(il codice per ora gira su un intel, però vorrei girasse pure su sun
ultrasparc a 64 bit e ho paura che questo incasini il tutto in modo
incredibile...)
In un mare di disperazione avevo pure pensato a definire la struttura in
assembler per essere sicuro dell'offset delle variabili della struttura,
ma mi sa che mi sto incasinando da solo....
Altrimenti avevo pensato a una struttura con un gpointer e un codice di
struttura da mettere in mezzo al primo puntatore e alla struttura
stessa. Certo che se posso fare il primo giochino che mi hai detto avrei
la soluzione più facile...


 incredibile...)
Se fai il casting si pensa il compilatore a trovare i campi chiamati con
l'offset giusto.

 l'offset giusto.
ma come faccio a castare se non so che struttura è?



Intendevo con la tecnica dello switch suggeritati.

di errori di puntatori a variabili che non esistono.
Non c'e' un modo per sapere che struttura stai trattando in
quel momento.  
Non va bene neanche il metodo delle union suggerito.
Una cosa e' sapere che i dati ci sono, una cosa e' sapere
che sono QUEI dati.
Una soluzione spicciola e' quella di usare un identificativo
in ognuna delle tue unit :
typedef { char nome[20] ; } struct_id ;
Lo usi come primo membro di ogni struttura da te definita,
lo valorizzi e ogni volta che qualcuno ti passa una
struttura di tipo qualsiasi, esamini il nome per
riconoscerla.
Non so se questo sistema possa funzionare.
--
CyberWalkie - walkietalkie(at)
libero.it

Intendevo con la tecnica dello switch suggeritati.
Inutile, e' un gatto che si morde la coda.
Come fa a fare uno switch (e quindi a discriminare) se a lui
serve proprio l'informazione per discriminare ???
--
CyberWalkie - walkietalkie(at)
libero.it


il metodo delle union da me suggerito non serviva a discriminare
qual'era la struttura indirizzata, ma solo a non usare il pointer void
castato. Per decidere quale struct fosse ho consigliato una variabile
esterna (inizializzata da chi inizializza il ptr, ovviamente), perche'
immaginavo che non potesse modificare le strutture.
ciao
donCiccio


In che casi questo sistema potrebbe non funzionare? per via
dell'allineamento dei dati della struct?

dell'allineamento dei dati della struct?
In realta' non c'entra l'allineamento.
E' che ho tirato le somme un po' troppo in fretta e forse
c'e' una soluzione migliore...
--
CyberWalkie - walkietalkie(at)
libero.it

di errori di puntatori a variabili che non esistono.
Non conosco il sistema e parto dal presupposto che i puntatori sul
sistema che usi siano tutti delle stesse dimensioni.
Non ho ben capito qual'e' il problema, BTW i puntatori sono indirizzi
e in linea di massima sono uguali fra loro indipendentemente dai dati
a cui puntano (e' bene comunque verificarlo).
Se devi fare operazioni sui puntatori di tipo diverso, ad esempio hai
un array di puntatori che puntano a dati diversi, il primo punta ad
una struttura, il secondo ad un intero, il terzo ad un float ecc.
Puoi castarli come ti pare, in genere si usa (void *), e fregartene
altamente dei dati a cui puntano.
Il problema si pone quando devi accedere ai dati attraverso il
puntatore, in tal caso sei obbligato a conoscerne il tipo.
Se hai un'array di puntatori che puntano a strutture di diverso tipo
(una sorta di lista) puoi prevedere all'interno di ogni struttura un
campo che ne identifichi il tipo.
ciao, acc.   
a...@libero.it

 c'e' una soluzione migliore...
a voler reimplementare il polimoirfismo in C? si passare al C++
:)
o almeno emulare il meccanismo della vtable

 serve proprio l'informazione per discriminare ???
risolto!
ho messo in mezzo una struttura tipo
typedef struct {
	void* pointer;
	int type_struct;
} pointer
e il puntatore void* punta alle varie struct.
E ho risolto così, che mi sembrava la via più veloce.


 c'e' una soluzione migliore...
ma se definisci una struttura di appoggio come hai suggerito
typedef struct{char nome [20];}struct_id;
e poi fai il casting di void* alla struttura cosě:
viod f(void *s)
{
    ((struct_id*)s) -> nome.....
    ..
}
siamo sicuri che il campo nome di struct_id abbia lo stesso identico
spiazzamento del campo nome delle atre strutture? forse si pechč si tratta
di char? e se utilizzavi un campo int invece non si poteva dire nulla a
riguardo?

riguardo?
Vale per tutti i tipi.
--
CyberWalkie - walkietalkie(at)
libero.it

:)
Che c'entra il polimorfismo ??
--
CyberWalkie - walkietalkie(at)
libero.it

 :)
ehm... sul c++ sono molto meno ferrato.... :-)
Oltre al fatto che dovrei ricominciare da capo.... :-(
-- 
Non c'č piů forza nella normalitŕ, c'č solo monotonia.


 Che c'entra il polimorfismo ??
scrivere p->func() o p->membro, senza sapere che cosa punta p, e' il 
polimorfismo del C++. o forse tu ne hai una definizione differente?

o almeno emulare il meccanismo della vtable
Io per anni ho lavorato a oggetti in C senza usare vtable...
ogni singolo oggetto conteneva i puntatori ai metodi (rispetto
alla vtable si spreca un po' di spazio in piu' ma si ha una
indirezione in meno).
Inoltre il vantaggio e' che si puo' modificare anche solo un
singolo metodo senza dover implementare un intero oggetto
derivato (comodo per inserire "eventi" come il clicked di
un bottone di una GUI... la versione standard punta a un
NOP ... chi e' interessato si puo' agganciare a quell'evento
senza dover derivare un altro oggetto).
Come sistema usavo il mettere come primo campo della struttura
l'oggetto da cui derivavo e di mettere un mio campo "id"
nell'oggetto base...
  typedef struct OBJECT
  {
    int id;        /* ID di oggetto */
    int refcount;  /* Immaginiamo di usare reference counting */
    void (*destroy)(struct OBJECT *me); /* distruttore */
  } Object;
  typedef struct SHAPE
  {
    Object o; /* Include la parte object base */
    void (*draw)(struct SHAPE *me,int color);
    ...
  } Shape;
  typedef struct TRIANGLE
  {
    Shape o; /* Include la parte shape (e object) */
    ...
  } Triangle;
In questo modo (usando il campo id) potevo fare il downcasting
corretto quando serviva. Mentre ad esempio "draw" puntava alla
funzione di disegno triangolo nel caso di una istanza di Triangle
(e' l'equivalente di una funzione virtuale).
Secondo me - a oggi - e' preferibile lavorare in C++ se si
devono fare cose simili (quando non ci sono controindicazioni
pesanti di altro tipo, ovviamente).
Andrea
--
Andrea Griffini, Programmer
http://www.netservers.com/~agriff

polimorfismo del C++. 
Questo non e' il polimorfismo del C++.
Innanzitutto il polimorfismo e' una caratteristica che entra
in gioco quando ci sono classi derivate che ereditano da
classi base dei metodi virtuali, compiendone l'override e
quando ci sono di mezzo puntatori e reference.
Non e' vero, poi, che scrivere p->membro scateni un
comportamento polimorfico.
Se ho una struttura Programmatore, che eredita da una
struttura Uomo e ho una funzione che accetta un puntatore a
una struttura Uomo e che fa uso del membro "anni" di Uomo,
non vuol dire che stia sfruttando dei comportamenti
polimorfici, vuol solo dire che all'interno della funzione
utilizzero' i dati di Programmatore che sono comuni alla
struttura Uomo, da cui essa eredita.
Secondo : il richiamo di un metodo per mezzo di un puntatore
(p->func()) non vuol dire che si stia necessariamente
mettendo in pratica un comportamento polimorfico.
Posso benissimo richiamare un metodo statico tramite un
puntatore a una classe base.  Il metodo viene ereditato
dalla classe figlia, ma essendo statico, se alla funzione
passo il puntatore alla classe figlia, verra' comunque e
sempre chiamato quello della madre.
Il problema del nostro amico sembra, piuttosto,
riconducibile a cio' che viene comunemente detta Run Time
Type Identification (RTTI) e che e' comune sia al C++ che a
Java, ma che non ha niente a che vedere col polimorfismo.
--
CyberWalkie - walkietalkie(at)
libero.it

 comportamento polimorfico.
ma tu 6 un esperto di mirror climbing? il post di ottavio si riferiva a 
puntatori a struct che avevano gli stessi membri, e cio' in c++ si 
ottiene tramite l'ereditarieta' e funzioni virtuali, *di solito*
se poi vuoi realizzarli in altro modo.... accomodati, e fammi sapere se 
ti viene meglio 
f/up dove appropriato

e funzioni virtuali, *di solito*
Non vedo cosa c'entrino le funzioni virtuali col problema di
Ottavio (i nomi delle persone si scrivono in *maiuscolo*).
Mi sa che il "mirror climbing" e' una specialita' tutta tua.
--
CyberWalkie - walkietalkie(at)
libero.it

comportamento polimorfico.
anzi; se con p->membro consideriamo un accesso ad una variabile (non
un metodo) non sarai mai un comportamento polimorfico; non mi risulta
che ci siano le "variabili membro virtuali" :-)
Anto
--
Antonio Cuni, 19 anni, studente
Brainbench C++ Master: 4.6, higher than 98% of all previous test takers.
C Language: 3.32, higher than 79% of all previous test takers.
Guida C/C++ di Programmazione.it: 
http://cpp.programmazione.it

che ci siano le "variabili membro virtuali" :-)
Esatto.
Mi sembra, tra l'altro, proprio il caso di Ottavio.
--
CyberWalkie - walkietalkie(at)
libero.it