Ho inserito il cast semplicemente per mostrare la disapprovazione del brutto buco nel sistema dei tipi, che consente a codice come il seguente frammento di compilare senza diagnostica, anche se non vengono utilizzati cast per determinare la conversione errata:
double d;
void *p = &d;
int *q = p;
Vorrei che non esistesse (e non lo sia in C ++) e quindi lancio. Rappresenta il mio gusto e la mia politica di programmazione. Non sto solo lanciando un puntatore, ma in effetti, lancio un voto e scacciando demoni di stupidità . Se non riesco davvero a scacciare la stupidità , almeno lasciami esprimere il desiderio di farlo con un gesto di protesta.
In effetti, una buona pratica è quella di avvolgere malloc
(e amici) con le funzioni che ritornano unsigned char *
, e sostanzialmente non usare mai void *
nel tuo codice. Se hai bisogno di un generico puntatore a qualsiasi oggetto, usa un char *
o unsigned char *
e hai i cast in entrambe le direzioni. L'unico rilassamento che può essere concesso, forse, è usare funzioni come memset
e memcpy
senza calchi.
Sul tema della fusione e la compatibilità C ++, se si scrive il codice in modo che si compila sia come C e C ++ (nel qual caso si deve lanciare il valore restituito malloc
quando si assegna a qualcosa di diverso void *
), si può fare un molto utile cosa per te: puoi usare le macro per il cast che si traducono in cast in stile C ++ durante la compilazione come C ++, ma riducono a un cast C durante la compilazione come C:
/* In a header somewhere */
#ifdef __cplusplus
#define strip_qual(TYPE, EXPR) (const_cast<TYPE>(EXPR))
#define convert(TYPE, EXPR) (static_cast<TYPE>(EXPR))
#define coerce(TYPE, EXPR) (reinterpret_cast<TYPE>(EXPR))
#else
#define strip_qual(TYPE, EXPR) ((TYPE) (EXPR))
#define convert(TYPE, EXPR) ((TYPE) (EXPR))
#define coerce(TYPE, EXPR) ((TYPE) (EXPR))
#endif
Se aderisci a queste macro, una semplice grep
ricerca nella tua base di codice per questi identificatori ti mostrerà dove sono tutti i tuoi cast, in modo da poter verificare se qualcuno di essi è errato.
Quindi, andando avanti, se compili regolarmente il codice con C ++, imporrà l'uso di un cast appropriato. Ad esempio, se si utilizza strip_qual
solo per rimuovere un const
o volatile
, ma il programma cambia in modo tale da coinvolgere una conversione di tipo, si otterrà una diagnostica e sarà necessario utilizzare una combinazione di cast per ottenere la conversione desiderata.
Per aiutarti ad aderire a queste macro, il compilatore GNU C ++ (non C!) Ha una bella funzionalità: una diagnostica opzionale che viene prodotta per tutte le occorrenze di cast in stile C.
-Wold-style-cast (solo C ++ e Objective-C ++)
Avvisa se viene utilizzato un cast vecchio stile (stile C) su un tipo non vuoto
all'interno di un programma C ++. I cast di nuovo stile (dynamic_cast,
static_cast, reinterpret_cast e const_cast) sono meno vulnerabili
effetti indesiderati e molto più facile da cercare.
Se il tuo codice C viene compilato come C ++, puoi utilizzare questa -Wold-style-cast
opzione per scoprire tutte le occorrenze della (type)
sintassi del casting che possono insinuarsi nel codice e dare seguito a questi diagnostici sostituendolo con una scelta appropriata tra le macro sopra (o un combinazione, se necessario).
Questo trattamento delle conversioni è la più grande giustificazione tecnica autonoma per lavorare in una "C pulita": il dialetto C e C ++ combinato, che a sua volta giustifica tecnicamente il valore di ritorno di malloc
.