Eu coloquei no elenco simplesmente para mostrar a desaprovação do buraco feio no sistema de tipos, que permite que códigos como o seguinte trecho sejam compilados sem diagnóstico, mesmo que nenhum elenco seja usado para provocar uma conversão ruim:
double d;
void *p = &d;
int *q = p;
Eu gostaria que isso não existisse (e não existe em C ++) e, por isso, fiz a transmissão. Representa meu gosto e minha política de programação. Não estou apenas lançando um ponteiro, mas efetivamente, votando e expulsando demônios da estupidez . Se eu realmente não posso expulsar a estupidez , pelo menos deixe-me expressar o desejo de fazê-lo com um gesto de protesto.
De fato, uma boa prática é agrupar malloc
(e amigos) com funções que retornam unsigned char *
e basicamente nunca usar void *
em seu código. Se você precisar de um ponteiro genérico para qualquer objeto, use a char *
ou unsigned char *
e tenha projeções nas duas direções. O único relaxamento que pode ser tolerado, talvez, é usar funções como memset
e memcpy
sem elencos.
No tópico fundição e compatibilidade com C ++, se você escrever seu código para que ele seja compilado tanto em C quanto em C ++ (nesse caso, você precisará converter o valor de retorno malloc
ao atribuí-lo a algo diferente de void *
), poderá fazer uma ajuda muito útil coisa para você: você pode usar macros para conversão que convertem para conversões no estilo C ++ ao compilar como C ++, mas reduzem para uma conversão C ao compilar como 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 você aderir a essas macros, uma simples grep
pesquisa na sua base de códigos por esses identificadores mostrará onde estão todas as suas transmissões, para que você possa verificar se alguma delas está incorreta.
A partir de agora, se você compilar regularmente o código com C ++, ele aplicará o uso de uma conversão apropriada. Por exemplo, se você usar strip_qual
apenas para remover um const
ou volatile
, mas o programa mudar de tal maneira que uma conversão de tipo esteja envolvida, você receberá um diagnóstico e precisará usar uma combinação de conversões para obter a conversão desejada.
Para ajudá-lo a aderir a essas macros, o compilador GNU C ++ (não C!) Possui um recurso bonito: um diagnóstico opcional produzido para todas as ocorrências de conversões no estilo C.
-Construção no estiloold (apenas C ++ e Objective-C ++)
Avisar se uma conversão de estilo antigo (estilo C) para um tipo não nulo é usada
dentro de um programa C ++. O novo estilo lança (dynamic_cast,
static_cast, reinterpret_cast e const_cast) são menos vulneráveis
para efeitos não intencionais e muito mais fáceis de pesquisar.
Se o seu código C for compilado como C ++, você poderá usar esta -Wold-style-cast
opção para descobrir todas as ocorrências da (type)
sintaxe de conversão que podem surgir no código e acompanhar esses diagnósticos, substituindo-o por uma escolha apropriada dentre as macros acima (ou um combinação, se necessário).
Esse tratamento de conversões é a maior justificativa técnica autônoma para trabalhar em um "C limpo": o dialeto C e C ++ combinado, que por sua vez tecnicamente justifica lançar o valor de retorno de malloc
.