Estou trabalhando em uma base de código antiga e praticamente toda chamada de free () usa uma conversão em seu argumento. Por exemplo,
free((float *)velocity);
free((float *)acceleration);
free((char *)label);
onde cada ponteiro é do tipo correspondente (e correspondente). Não vejo sentido em fazer isso. É um código muito antigo, então fico me perguntando se é uma coisa de K&R. Nesse caso, desejo realmente oferecer suporte aos compiladores antigos que possam ter exigido isso, então não quero removê-los.
Existe uma razão técnica para usar esses modelos? Não vejo nem uma razão pragmática para usá-los. Qual é o sentido de nos lembrar do tipo de dados antes de liberá-lo?
Edição: Esta pergunta não é uma duplicata da outra pergunta. A outra pergunta é um caso especial desta pergunta, que eu acho óbvio se os eleitores próximos leiam todas as respostas.
Colophon: Estou dando a "resposta constante" a marca de seleção porque é uma verdadeira razão genuína pela qual isso pode precisar ser feito; no entanto, a resposta sobre ser um costume pré-ANSI C (pelo menos entre alguns programadores) parece ser o motivo pelo qual foi usada no meu caso. Muitos pontos positivos por muitas pessoas aqui. Obrigado por suas contribuições.
void*
no C pré-padrão, mas apenaschar*
. Portanto, se suas descobertas arqueológicas revelarem código que lança o parâmetro para free (), acredito que deve ser daquele período ou ser escrito por uma criatura daquela época. Não consigo encontrar nenhuma fonte para isso, então evitarei responder.Respostas:
A conversão pode ser necessária para resolver os avisos do compilador, se os ponteiros estiverem
const
. Aqui está um exemplo de código que causa um aviso sem lançar o argumento free:E o compilador (gcc 4.8.3) diz:
Se você usar
free((float*) velocity);
o compilador para de reclamar.fonte
float*
antes da liberação. Eu tenteifree((void *)velocity);
com o gcc 4.8.3. Claro que não iria funcionar com um compilador antigoconst char *p
como argumento e depois a libera, a coisa certa a fazer não é converterp
parachar*
antes de chamar de graça. É para não declarar que está recebendoconst char *p
em primeiro lugar, pois ele modifica*p
e deve ser declarado da mesma forma. (E se ele leva um ponteiro const em vez de ponteiro para const,int *const p
, você não precisa de elenco desde que é realmente legal e, portanto, funciona bem sem o elenco.)O C pré-padrão não tinha
void*
mas apenaschar*
, então você tinha que converter todos os parâmetros passados. Se você encontrar o código C antigo, poderá encontrar esses elencos.Pergunta semelhante com referências .
Quando o primeiro padrão C foi lançado, os protótipos para malloc e free mudaram de ter
char*
para ovoid*
que eles ainda têm hoje.E, é claro, no padrão C, esses modelos são supérfluos e prejudicam a legibilidade.
fonte
free
para o mesmo tipo que já é?free
funcionam no padrão C (você não precisa converter). Eu não li a 1ª edição, então não sei dizer se eles também estavam confusos nos tempos pré-padrão dos anos 80.void*
, mas também não tinha protótipos de função, portanto, lançar o argumento defree
ainda era desnecessário mesmo em K&R (supondo que todos os tipos de ponteiros de dados usassem a mesma representação).char *
. Que sentido faria em compiladores antigos semvoid
? O que esses elencos atingiriam?Aqui está um exemplo em que o free falharia sem um elenco:
Em C, você pode receber um aviso (recebi um no VS2012). Em C ++, você receberá um erro.
Casos raros à parte, o elenco apenas incha o código ...
Edit: Eu lancei para
void*
nãoint*
demonstrar a falha. Funcionará da mesma formaint*
que será convertidovoid*
implicitamente.int*
Código adicionado .fonte
void *
, mas parafloat *
echar *
. Esses elencos não são apenas estranhos, eles estão errados.free(p)
falharia? Isso daria um erro do compilador?const
ponteiros qualificadores, obviamente.volatile
existe desde que C foi padronizado, se não mais. Foi não acrescentou em C99.Motivo antigo: 1. Ao usar
free((sometype*) ptr)
, o código é explícito sobre o tipo que o ponteiro deve ser considerado como parte dafree()
chamada. A conversão explícita é útil quandofree()
é substituída por um (faça você mesmo)DIY_free()
.A
DIY_free()
era (é) uma maneira, especialmente no modo de depuração, de fazer uma análise em tempo de execução do ponteiro sendo liberado. Isso geralmente é associado a umDIY_malloc()
para adicionar sentenciais, contagens globais de uso de memória, etc. Meu grupo usou essa técnica por anos antes que ferramentas mais modernas fossem exibidas. Obrigava que o item que estava sendo liberado fosse lançado para o tipo que foi originalmente alocado.Moderno: Evitar
const
evolatile
avisos, conforme abordado por Manos Nikolaidis @ e @egur . Pensamento gostaria de observar os efeitos dos 3 eliminatórias :const
,volatile
, erestrict
.Adicionado
char * restrict *rp2
por @R .. comentáriofonte
restrict
não é um problema devido ao local onde está colocado - afeta o objeto erp
não o tipo apontado. Se você tivessechar *restrict *rp
, então isso importaria.Aqui está outra hipótese alternativa.
Fomos informados de que o programa foi escrito antes da C89, o que significa que não pode haver algum tipo de incompatibilidade com o protótipo de
free
, porque não apenas não havia tal coisaconst
nemvoid *
antes da C89, não havia tal coisa como um protótipo de função anterior a C89.stdlib.h
em si foi uma invenção do comitê. Se os cabeçalhos do sistema se preocupassem em declararfree
, eles teriam feito assim:Agora, o ponto principal aqui é que a ausência de protótipos de função significava que o compilador não fazia verificação de tipo de argumento . Ele aplicou as promoções de argumentos padrão (as mesmas que ainda se aplicam a chamadas de funções variadas) e foi isso. A responsabilidade de alinhar os argumentos em cada local da chamada com as expectativas do receptor cabe inteiramente ao programador.
No entanto, isso ainda não significa que era necessário lançar o argumento
free
na maioria dos compiladores K&R. Uma função comodeveria ter sido compilado corretamente. Então, acho que o que temos aqui é um programa escrito para lidar com um compilador de buggy para um ambiente incomum: por exemplo, um ambiente em que
sizeof(float *) > sizeof(int)
o compilador não usaria a convenção de chamada apropriada para ponteiros, a menos que você os projete no momento da chamada.Não conheço esse ambiente, mas isso não significa que não exista. Os candidatos mais prováveis que vêm à mente são os compiladores "minúsculos C" reduzidos para micros de 8 e 16 bits no início dos anos 80. Também não ficaria surpreso ao saber que os primeiros Crays tinham problemas como esse.
fonte
free aceita apenas ponteiros não-const como parâmetro. Portanto, no caso de ponteiros const, é necessária a conversão explícita para um ponteiro não const.
Não é possível liberar ponteiros const em C
fonte