Por que anular o valor de retorno do free?


82

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 freeser 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.


Algumas explicações possíveis podem ser encontradas aqui: stackoverflow.com/questions/689677/…
Timbo

3
Por curiosidade, qual é a data de publicação do seu livro em C? (Que livro é esse?) Se é antes de 1995, pode haver alguma justificativa para isso - os compiladores C padrão não eram onipresentes antes. Se for publicado depois disso e ainda contiver o elenco (e nenhuma explicação do porquê), preocupe-se com os outros maus hábitos que está ensinando a você. Obtenha um livro mais recente!
Jonathan Leffler


3
@ JonathanLeffler, como mencionado no meu post original, o livro foi publicado em 1997 e estava usando o UNIX 4.0d. O livro é "Programação com POSIX Threads", de David R. Butenhof. Até agora, foi muito informativo e foi escrito por um dos colaboradores originais do padrão de threads POSIX.
Adam Johnston

6
Eu tenho usado minha cópia disso na última semana - sim, ainda é útil. Foi escrito à beira do 'padrão onipresente C' (eu disse 'por volta de 1995'). O 'UNIX 4.0d' soa como o Digital UNIX - foi onde Butenhof trabalhou e o prefácio menciona isso. Trate o elenco free()como uma singularidade no livro que você não precisa imitar. Era semi-relevante há muito tempo, mas não é mais relevante.
Jonathan Leffler

Respostas:


100

Se estamos falando sobre o padrão free função , seu protótipo é

void free(void *ptr);

Portanto, o elenco é completamente inútil.
Agora, algumas especulações.

O autor pode ter esquecido de incluir o stdlib.hcabeçalho que declara esse protótipo; portanto, o compilador está assumindo o tipo de retorno como int. 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- voidfunção. Esses avisos geralmente são silenciados ao adicionar o elenco a void.


50
Mas observe que, se o elenco foi apresentado pelo motivo especulado, usá-lo para silenciar o aviso está incorreto . Nesse caso, o compilador atribuirá um tipo diferente freedo 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.
John Bollinger

11
Notavelmente, os exemplos em "Programação com threads POSIX" repetidamente não incluem os cabeçalhos padrão relevantes. Talvez essa tenha sido uma prática ruim do autor, eles poderiam estar usando uma configuração de compilador não padrão que incluísse todas as bibliotecas padrão por padrão.
Lundin

74

Seria uma coisa legada!

Antes de haver um padrão C, a free()função seria (implicitamente) do tipo int- 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 escreveria extern char *malloc();(talvez sem oextern ) para as funções de alocação (da mesma forma para calloc()e realloc()), 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 provavelmente lint) que "o valor de retorno free()é deliberadamente ignorado" para evitar uma reclamação. Mas seria melhor adicionar <stdlib.h>e deixar sua declaração extern void free(void *vp);informar lintou 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 de char *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.)


9
Acabei de abrir uma cópia da K&R, 1ª edição, que contém uma implementação da free()on p. 177 que retorna implicitamente int.
ex nihilo

9
É claro - voidfoi 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 retornou int) 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 as intregras 'implícita ' e 'declaração implícita de função'. Nem todo o código do mundo alcançou.
Jonathan Leffler

5
Op afirma que o livro foi escrito em 1997. O que você está falando aqui é muito cedo "K&R C" pré-padrão e parece improvável que alguém escreva um livro sobre isso. O único livro que existia até onde eu sabia era realmente a 1ª edição da K&R.
Lundin

Era uma prática frequente (se quixotesca) não incluir cabeçalhos se você pensasse que poderia se safar com declarações implícitas, porque as pessoas pensavam que isso reduziria o tempo de criação.
Spencer

Alguém usa um (void)elenco para printf()??
Luis Colorado

11

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:

Se a expressão que precede a lista de argumentos entre parênteses em uma chamada de função consistir apenas em um identificador, e se nenhuma declaração for visível para esse identificador, o identificador será implicitamente declarado exatamente como se, no bloco mais interno que contém a chamada de função, a declaração

extern int identifier();

apareceu.

Mas isso é estranho, porque eles não estão lançando o resultado de mallocnenhum deles malloce freeestã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 freenão retorna nenhum resultado.


5
Só porque uma linguagem é padronizada não significa que todos atualizem instantaneamente sua cadeia de ferramentas e código para se adequar a ela. É plausível que o "K&R" C à moda antiga permaneça por mais 8 anos. Ainda assim, concordo que é estranho que uma ferramenta de análise estática exija uma conversão para, freemas não para malloc.
dan04 11/03

4
@ dan04 Você costuma usar o resultado do malloc;) Eu não sou fã de escrever coisas como (void) printf (...) para parar o compilador cuspir avisos, mas "deve compilar sem avisos, mesmo os idiotas" é algo que acontece em muitos projetos.
richardb 11/03
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.