[C] Compatibilità tipi [risolto]

Forum dedicato alla programmazione.

Moderatore: Staff

Regole del forum
1) Citare in modo preciso il linguaggio di programmazione usato.
2) Se possibile portare un esempio del risultato atteso.
3) Leggere attentamente le risposte ricevute.
4) Scrivere i messaggi con il colore di default, evitare altri colori.
5) Scrivere in Italiano o in Inglese, se possibile grammaticalmente corretto, evitate stili di scrittura poco chiari, quindi nessuna abbreviazione tipo telegramma o scrittura stile SMS o CHAT.
6) Appena registrati è consigliato presentarsi nel forum dedicato.

La non osservanza delle regole porta a provvedimenti di vari tipo da parte dello staff, in particolare la non osservanza della regola 5 porta alla cancellazione del post e alla segnalazione dell'utente. In caso di recidività l'utente rischia il ban temporaneo.
Rispondi
Dani
Linux 4.x
Linux 4.x
Messaggi: 1447
Iscritto il: mer 26 apr 2006, 1:52
Desktop: gnome
Distribuzione: arch

[C] Compatibilità tipi [risolto]

Messaggio da Dani »

In un programma ho definito un tipo struct con diversi membri al suo interno, eterogenei, alcuni propri del C mentre altri definiti altrove, sempre nello stesso programma.
Secondariamente ho una funzione che riceve l'indirizzo di una variabile del tipo struct incriminato. Questa funzione ha il compito di analizzare una stringa e "compilare" i membri della struttura.
Ora il problema è avere un puntatore generico, che riesca a puntare a un membro qualsiasi della struttura e che riesca a modificarlo attraverso un assegnamento.

Ad esempio, ho la struttura:

Codice: Seleziona tutto

struct x {
   char  *a;
   xyz_t *b;
}
In una funzione devo dichiarare un puntatore ptr "compatibile" con tutti i membri e assegnargli l'indirizzo di uno di essi.

Codice: Seleziona tutto

ptr = &x->s;
A questo punto devo assegnare a ptr il valore di ritorno di una seconda funzione:

Codice: Seleziona tutto

*ptr = f()
quest'assegnamento deve andare a finire nel membro puntato da ptr, s in questo caso, esattamente come se avessi usato:

Codice: Seleziona tutto

x->s = f();
Ora come ora sto usando un int*:

Codice: Seleziona tutto

int *ptr;
ptr = (int *) &x->s;
*ptr = (int) f();
il programma funziona correttamente, ma durante le compilazione ho:

Codice: Seleziona tutto

warning: dereferencing type-punned pointer will break strict-aliasing rules
Ci sono alternative al puntatore int e posso evitare in qualche modo quel warning senza togliere dal makefile -O2 -Wall e senza aggiungere -fno-strict-aliasing ?
Diciamo che la mia è soprattuto una curiosità, come ho già detto il programma funziona, ma non sono sicuro di agire nel modo corretto. :roll:
Ultima modifica di Dani il ven 8 ago 2008, 4:04, modificato 1 volta in totale.

Avatar utente
ZeD
Linux 1.x
Linux 1.x
Messaggi: 112
Iscritto il: ven 28 ott 2005, 12:30
Slackware: 12.1
Località: Terra

Re: [C] Compatibilità tipi

Messaggio da ZeD »

Dani ha scritto:In un programma ho definito un tipo struct con diversi membri al suo interno, eterogenei, alcuni propri del C mentre altri definiti altrove, sempre nello stesso programma.
Secondariamente ho una funzione che riceve l'indirizzo di una variabile del tipo struct incriminato. Questa funzione ha il compito di analizzare una stringa e "compilare" i membri della struttura.
Ora il problema è avere un puntatore generico, che riesca a puntare a un membro qualsiasi della struttura e che riesca a modificarlo attraverso un assegnamento.
Perdonami, ma non ho capito a che ti serve un "puntatore generico".
Cioé, se sai che &x->a è un "char*" perchè non usi una variabile di tipo "char*"?

Ad esempio, ho la struttura:

Codice: Seleziona tutto

struct x {
   char  *a;
   xyz_t *b;
}
In una funzione devo dichiarare un puntatore ptr "compatibile" con tutti i membri e assegnargli l'indirizzo di uno di essi.

Codice: Seleziona tutto

ptr = &x->s;
...s? (vabe', presumo che sia un campo tipo a o b)
A questo punto devo assegnare a ptr il valore di ritorno di una seconda funzione:

Codice: Seleziona tutto

*ptr = f()
quest'assegnamento deve andare a finire nel membro puntato da ptr, s in questo caso, esattamente come se avessi usato:

Codice: Seleziona tutto

x->s = f();
Ora come ora sto usando un int*:

Codice: Seleziona tutto

int *ptr;
ptr = (int *) &x->s;
*ptr = (int) f();
il programma funziona correttamente, ma durante le compilazione ho:

Codice: Seleziona tutto

warning: dereferencing type-punned pointer will break strict-aliasing rules
Ci sono alternative al puntatore int e posso evitare in qualche modo quel warning senza togliere dal makefile -O2 -Wall e senza aggiungere -fno-strict-aliasing ?
Beh, potresti definire ptr di tipo void*, e toglierti i casting di torno... ma non ho capito perché non puoi usare "il tipo giusto"

Diciamo che la mia è soprattuto una curiosità, come ho già detto il programma funziona, ma non sono sicuro di agire nel modo corretto. :roll:
mmm
"funziona" non credo sia sufficiente: a memoria non ci sono errori solo perché su x86 un int* e un void* hanno la stessa dimensione... ma non ci fare affidamento

Dani
Linux 4.x
Linux 4.x
Messaggi: 1447
Iscritto il: mer 26 apr 2006, 1:52
Desktop: gnome
Distribuzione: arch

Re: [C] Compatibilità tipi

Messaggio da Dani »

ZeD ha scritto:Perdonami, ma non ho capito a che ti serve un "puntatore generico".
Cioé, se sai che &x->a è un "char*" perchè non usi una variabile di tipo "char*"?
Perchè la funzione non deve modificare sempre un char* ma anche variabili di tipo differente. Il suo comportamento varia in base ai parametri ricevuti, e sempre in base ad essi decido su quale variabile (e soprattutto di che tipo) agire.
Potrei effettuare gli assegnamenti direttamente sui membri della struttura, ma è una questione di leggibilità del codice (probabilmente solo per me :))
...s? (vabe', presumo che sia un campo tipo a o b)
Colpa dell'ora :D
Comunque si, intendevo a o b.
Beh, potresti definire ptr di tipo void*, e toglierti i casting di torno... ma non ho capito perché non puoi usare "il tipo giusto"
Con un puntatore a void come posso modificare l'indirizzo di una variabile non potendolo dereferenziare ?

Avatar utente
absinthe
Iper Master
Iper Master
Messaggi: 2354
Iscritto il: dom 15 mag 2005, 0:00
Nome Cognome: Matteo Nunziati
Slackware: 12.1 - defunct
Kernel: 2.6.32-5-amd64
Desktop: gnome
Distribuzione: debian squeeze
Località: Prato
Contatta:

Re: [C] Compatibilità tipi

Messaggio da absinthe »

se te ne freghi dell'ansi e usi i tool gnu esiste la macro typeof !
altrimenti puoi usare un puntatore void ma poi IMHO _devi_ fare il cast se vuoi gestire il contenuto della variabile...
se non vuoi accedere direttamente alla struttura e non vuoi incasinarti la vita IMHO devi crearti dei "metodi" (ma mi pare inutile)

Codice: Seleziona tutto

typedef struct _a_useless_struct {
int a;
double b;
another_struct *my_stuff;
} my_data;

void my_data_set_int(ptr_to_my_data *ptr, int set_a_with_this_value) {
    ptr->a = set_a_with_this_value;
}

void my_data_set_double(ptr_to_my_data *ptr, double set_b_with_this_value) {
    ptr->b = set_b_with_this_value;
}

void my_data_set_another_struct_address(ptr_to_my_data *ptr, another_struct * set_my_stuff_with_this_address) {
    ptr->my_stuff = set_my_stuff_with_this_address;
}
detto ciò per chiarire il concetto, puoi usare l'overloading delle funzioni per fare quello che ti serve!

Codice: Seleziona tutto

typedef struct _a_useless_struct {
int a;
double b;
another_struct *my_stuff;
} my_data;

//zero-th overloaded version for int: first instance of my_data_set_item
void my_data_set_item(ptr_to_my_data *ptr, int set_a_with_this_value) {
    ptr->a = set_a_with_this_value;
}
//first overloaded version for double
void my_data_set_item(ptr_to_my_data *ptr, double set_b_with_this_value) {
    ptr->b = set_b_with_this_value;
}
//second overloaded version for addresses
void my_data_set_item(ptr_to_my_data *ptr, another_struct * set_my_stuff_with_this_address) {
    ptr->my_stuff = set_my_stuff_with_this_address;
}
M

Dani
Linux 4.x
Linux 4.x
Messaggi: 1447
Iscritto il: mer 26 apr 2006, 1:52
Desktop: gnome
Distribuzione: arch

Re: [C] Compatibilità tipi

Messaggio da Dani »

Credo di aver risolto, usando un puntatore a puntatore a void.

Codice: Seleziona tutto

void **ptr;
ptr = (void **) &mystruct->type_ptr;
*ptr = (type_cast *) value;
Così facendo non ottengo warning, ma mi restano due dubbi:
- Questa soluzione presenta problemi su architetture non x86 ?
- Se il void** ptr punta ad un int, *ptr = (int *) atoi ("10") è corretto ?

[edit]
No non è vero, anche così facendo gcc mi dà il warning se dal makefile non tolgo -O2 o -fno-strict-aliasing (con -O2 abilitato). :(

Dani
Linux 4.x
Linux 4.x
Messaggi: 1447
Iscritto il: mer 26 apr 2006, 1:52
Desktop: gnome
Distribuzione: arch

Re: [C] Compatibilità tipi

Messaggio da Dani »

Anche se qui menzionano il termine di "puntatore generico", a quanto pare, questo in C non esiste.
Un void* non fa al caso mio, in quanto non dereferenziabile, mentre un void** sembra essere non portabile.
Anche l'overloading delle funzioni in C non è una cosa fattibile.
Ho risolto semplicemente modificando il codice, alla fine mi stavo solo complicando la vita inutilmente !

Avatar utente
absinthe
Iper Master
Iper Master
Messaggi: 2354
Iscritto il: dom 15 mag 2005, 0:00
Nome Cognome: Matteo Nunziati
Slackware: 12.1 - defunct
Kernel: 2.6.32-5-amd64
Desktop: gnome
Distribuzione: debian squeeze
Località: Prato
Contatta:

Re: [C] Compatibilità tipi

Messaggio da absinthe »

Dani ha scritto: Anche l'overloading delle funzioni in C non è una cosa fattibile.
why :?:

M

Dani
Linux 4.x
Linux 4.x
Messaggi: 1447
Iscritto il: mer 26 apr 2006, 1:52
Desktop: gnome
Distribuzione: arch

Re: [C] Compatibilità tipi

Messaggio da Dani »

absinthe ha scritto:
Dani ha scritto: Anche l'overloading delle funzioni in C non è una cosa fattibile.
why :?:

M
Non è previsto in c !
Compilando questo:

Codice: Seleziona tutto

void f (int x) {
 return;
 }
void f (double y) {
 return;
 }
 int main (void) {
  return 0;
 }
ottengo:

Codice: Seleziona tutto

error: conflicting types for 'f'
error: previous definition of 'f' was here

Avatar utente
absinthe
Iper Master
Iper Master
Messaggi: 2354
Iscritto il: dom 15 mag 2005, 0:00
Nome Cognome: Matteo Nunziati
Slackware: 12.1 - defunct
Kernel: 2.6.32-5-amd64
Desktop: gnome
Distribuzione: debian squeeze
Località: Prato
Contatta:

Re: [C] Compatibilità tipi [risolto]

Messaggio da absinthe »

opporc... #-o vedi che succede a fare tutto con il sottogruppo c del c++ :oops:

M

Rispondi