Newsgroup: it.comp.lang.c
Titolo: Funzione che gestisce variabili generiche (int, unsigned int, char, unsigned char)

Nel mio programma ho alcune variabili che rappresentano dei parametri
di funzionamento. Questi parametri, tipicamente numerici, possono essere
memorizzati in variabili di vario tipo: char, unsigned char, int,
unsigned int.
Devo scrivere una funzione in C generica, valida per un qualsiasi parametro,
che modifichi il suo valore. Per semplicità, diciamo che deve incrementare
la variabile di una unità.
A questa variabile passo il puntatore ad una struct relativa al parametro
in cui sono memorizzate varie informazioni, tra cui il puntatore alla
variabile da modificare. Ma che tipo di puntatore devo mettere se non
conosco il tipo della variabile?
Ho pensato ad alcune soluzioni. Una è quella di inserire nella struct
quattro puntatori diversi, di cui uno solo sarà non NULL:
struct {
   unsigned char  *p_uchar;
   signed char    *p_schar;
   unsigned int   *p_uint;
   signed int     *p_sint;
   ...
} param;
Però sapete quanto spazio spreco? E per incrementare il valore del parametro
devo fare:
if( p_uchar )
   *p_uchar++;
else if( p_schar )
   *p_schar++;
else if( p_uint )
   *p_uint++;
else if( p_sint )
   *p_sint++;
Poco efficiente davvero.
Un'altra soluzione è quella di utilizzare un membro della struct che
memorizza il tipo di dato:
#define PARAMTYPE_UCHAR 1
#define PARAMTYPE_SCHAR 2
#define PARAMTYPE_UINT  3
#define PARAMTYPE_SINT  4
struct {
   int  type;
   void *p_value;
   ...
};
Risparmio spazio, rispetto alla soluzione precedente, ma l'incremento è
comunque inefficiente (non so se le parentesi sono corrette):
if( type==PARAMTYPE_UCHAR )
   (*(unsigned char *)p_value)++;
else if( type==PARAMTYPE_SCHAR )
   (*(signed char *)p_value)++;
...
Possibile che non esista qualche altra possibilità in C per incrementare
una variabile numerica senza conoscerne il tipo? Come fa la printf()?
Eppure io passo indifferentemente signed char e signed int, utilizzando
l'unico parametro %d, e funziona alla grande. L'unico problema capita se
le variabili sono unsigned (devo usare %u).

 le variabili sono unsigned (devo usare %u).
tipicamente un problema del genere si risolve passando due variabili: un 
puntatore generico ed un indicatore di tipo, lavorando poi con i cast 
all'interno della funzione.
in maniera molto simile a come lavorano printf e piu' precisamente scanf

 l'unico parametro %d, e funziona alla grande.
Le tratta tutte come un int, visto che passando %d sei tu che
dici di trattarle come tale. Fino a quando ti va bene, ti
va bene. Poi, ogni tanto, quacuno scrive su qualche NG
chiedendo come mai la porcata che ha fatto fino al giono
prima e che "funzionava alla grande", cambiando un'iniezia
non funziona piu'...
HTH
C:\>iao Angelo
-- 
Posted via Mailgate.ORG Server - 
http://www.Mailgate.ORG

mmm ha scritto:

Sì, alla fine penso proprio che sia l'unica soluzione...
Ma in C++ è la stessa cosa?

 non funziona piu'...
Questa non l'ho capita...

 Questa non l'ho capita...
Nemmeno io, se si programma in modo attento e "portabile"
tutto funziona sempre.  :-)
Giorgio Silvestri

 Per  questo motivo %d funziona sempre (%u se diventa unsigned).
Ah, ecco. Ora si spiega tutto...
Sei stato veramente molto gentile e chiaro nelle spiegazioni.
Mille grazie.

 Questa non l'ho capita...
Cercare scorciatoie "furbe" per evitare qualche riga di
codice NON E' MAI UNA COSA SAGGIA. Questi "lampi
di genio" prima o poi si pagano.
C:\>iao Angelo


No. Non č questo il motivo.
Infatti dire che funziona il seguente:
char pippo = 10;
int  pluto = pippo;
non implica che funziona anche nel nostro caso
per gli argomenti delle funzioni!
Bisogna dire espressamente che in questo caso la
"default-argument-promotion" segue le regole
della 'integer-promotion' per i parametri interi ma per
esempio NON segue il normale comportamento
per la gestione dei tipi reali! Infatti float
diventa double, e questo NON avviene normalmente se tutti e due gli
argomenti di un operatore sono float!
Quindi a priori si sarebbe potuta scegliere anche una
diversa tecnica per gli interi.
Mentre si č deciso che viene applicata la integer promotion. :-)
--
Giorgio Silvestri


Forse č il caldo ...
Ma il mio post iniziale era corretto!
Ovviamente si possono inizializzare const tag come quelle dell'esempio.
In definitiva:
Con C89 giusto.
Con C99 puoi anche l'altro (cioč o uno o l'altro).
--
Giorgio Silvestri