Estou lendo um livro ( Programming with POSIX Threads by Butenhof, 1997) que usa C e me deparei com a seguinte linha:
(void)free(data);
Aqui, data
é apenas um ponteiro para uma estrutura alocada,
data = malloc(sizeof(my_struct_t));
Por que o resultado de free
ser lançado para void
?
Do meu entendimento de C, isso não parece fazer sentido por dois motivos:
- A função livre já retorna
void
- O código não está usando o valor de retorno (nem está sendo atribuído a uma variável)
O livro foi escrito em 1997. Isso é algum tipo de coisa legada?
O autor menciona que os exemplos foram executados no Digital Unix 4.0d, mas ainda não consigo imaginar uma razão para lançar o resultado de uma função se você não for usar esse resultado.
free()
como uma singularidade no livro que você não precisa imitar. Era semi-relevante há muito tempo, mas não é mais relevante.Respostas:
Se estamos falando sobre o padrão
free
função , seu protótipo éPortanto, o elenco é completamente inútil.
Agora, algumas especulações.
O autor pode ter esquecido de incluir o
stdlib.h
cabeçalho que declara esse protótipo; portanto, o compilador está assumindo o tipo de retorno comoint
. Agora, durante a análise estática desse código, o compilador estava alertando sobre o valor de retorno não utilizado do que ele considera uma não-void
função. Esses avisos geralmente são silenciados ao adicionar o elenco avoid
.fonte
free
do que realmente tem, com o resultado de que a chamada possui um comportamento indefinido (supondo a semântica C90, em que a chamada de uma função não declarada não exibe inerentemente UB em todos os casos). Na prática, é plausível que isso resultaria em bona fide mau comportamento em alguns sistemas. A solução correta é fornecer uma declaração correta para a função.Seria uma coisa legada!
Antes de haver um padrão C, a
free()
função seria (implicitamente) do tipoint
- porque ainda não havia um tipo confiávelvoid
para ele retornar. Não houve valor retornado.Quando o código foi modificado pela primeira vez para funcionar com compiladores C padrão, provavelmente não foi incluído
<stdlib.h>
(porque não existia antes do padrão). Código antigo escreveriaextern char *malloc();
(talvez sem oextern
) para as funções de alocação (da mesma forma paracalloc()
erealloc()
), e não precisaria declararfree()
. E o código então converteria o valor de retorno no tipo correto - porque isso era necessário em pelo menos alguns sistemas (incluindo o que aprendi C).Algum tempo depois, o
(void)
elenco foi adicionado para informar ao compilador (ou, mais provavelmentelint
) que "o valor de retornofree()
é deliberadamente ignorado" para evitar uma reclamação. Mas seria melhor adicionar<stdlib.h>
e deixar sua declaraçãoextern void free(void *vp);
informarlint
ou ao compilador que não havia valor a ignorar.JFTR: Em meados dos anos 80, o ICL Perq estava originalmente em uma arquitetura orientada a palavras e o
char *
endereço de um local de memória era um número muito diferente do 'qualquer ponteiro de qualquer outra coisa' para o mesmo local. Era crucial declarar dechar *malloc()
alguma forma; era crucial converter o resultado para qualquer outro tipo de ponteiro. O elenco realmente mudou o número usado pela CPU. (Também houve muita alegria quando a memória principal em nossos sistemas foi atualizada de 1 MiB para 2 MiB - desde que o kernel usava cerca de 3/4 MiB, isso significava que os programas do usuário podiam usar 1 1/4 MiB antes da paginação etc.)fonte
free()
on p. 177 que retorna implicitamenteint
.void
foi adicionado a alguns sistemas (sistema Unix III, talvez) antes do lançamento do padrão, mas isso não fazia parte do C quando o K&R 1st Edn foi escrito (1978). Uma função que não retornou um valor foi declarada sem um tipo de retorno (o que significava que retornouint
) e, desde que você não usasse o valor que não foi retornado, não havia problema. O padrão C90 tinha que tratar esse tipo de código como válido - teria falhado tristemente como um padrão. Mas C99 removeu asint
regras 'implícita ' e 'declaração implícita de função'. Nem todo o código do mundo alcançou.(void)
elenco paraprintf()
??Este elenco não é necessário. Provavelmente não teria sido na época, pois C havia sido padronizado na forma de C89.
Se tivesse sido, teria sido devido a declaração implícita . Isso geralmente significava que a pessoa que estava escrevendo o código esqueceu
#include <stdlib.h>
e estava sendo usado um analisador estático. Esta não é a melhor solução alternativa e uma idéia muito melhor teria sido apenas em#include <stdlib.h>
vez disso. Aqui estão algumas palavras do C89 sobre declaração implícita:Mas isso é estranho, porque eles não estão lançando o resultado de
malloc
nenhum delesmalloc
efree
estão no mesmo arquivo de cabeçalho.Também é possível que isso seja apenas um erro ou alguma maneira de dizer ao leitor que
free
não retorna nenhum resultado.fonte
free
mas não paramalloc
.