Czytam książkę ( Programowanie z wątkami POSIX autorstwa Butenhof, 1997), która używa C, i natrafiłem na następujący wiersz:
(void)free(data);
Tutaj data
jest tylko wskaźnikiem do przydzielonej struktury,
data = malloc(sizeof(my_struct_t));
Dlaczego jest wynikiem free
jest wrzucony do void
?
Z mojego rozumienia C wydaje się to nie mieć sensu z dwóch powodów:
- Funkcja bezpłatna już powraca
void
- Kod nie używa wartości zwracanej (nawet nie jest przypisany do zmiennej)
Książka została napisana w 1997 roku. Czy jest to jakaś spuścizna?
Autor wspomina, że przykłady uruchomiono na Digital Unix 4.0d, ale wciąż nie wyobrażam sobie powodu, aby kiedykolwiek rzucić wynik funkcji, jeśli nie zamierzasz użyć tego wyniku.
free()
jako osobliwość w książce, której nie musisz naśladować. Dawno temu było to na wpół trafne, ale już nie ma znaczenia.Odpowiedzi:
Jeśli mówimy o
free
funkcji standardowej, to jej prototyp toDlatego obsada jest całkowicie bezużyteczna.
Teraz trochę spekulacji.
Autor mógł zapomnieć o dołączeniu
stdlib.h
nagłówka deklarującego ten prototyp, więc kompilator przyjmuje jego typ zwracany jakoint
. Teraz podczas analizy statycznej tego kodu kompilator ostrzegał o niewykorzystanej wartości zwracanej tego, co uważa zavoid
niefunkcjonalne. Takie ostrzeżenia są zwykle wyciszane przez dodanie obsadyvoid
.źródło
free
niż w rzeczywistości, w wyniku czego wywołanie ma nieokreślone zachowanie (zakładając semantykę C90, gdzie wywołanie funkcji niezadeklarowanej nie we wszystkich przypadkach wykazuje UB). W praktyce, jest to prawdopodobne, że spowoduje bona fide złe zachowanie na niektórych systemach. Prawidłowym rozwiązaniem jest podanie poprawnej deklaracji dla funkcji.Byłoby to spuścizna!
Zanim
free()
pojawiłby się standard C, funkcja byłaby (domyślnie) typuint
- ponieważ nie było jeszcze wiarygodnego typu,void
aby mogła ona zwrócić. Nie zwrócono żadnej wartości.Kiedy kod został po raz pierwszy zmodyfikowany do pracy ze standardowymi kompilatorami języka C, prawdopodobnie nie zawierał
<stdlib.h>
(ponieważ nie istniał przed standardem). Stary kod pisałbyextern char *malloc();
(być może bezextern
) dla funkcji alokacji (podobnie dlacalloc()
irealloc()
) i nie musiał deklarowaćfree()
. A kod rzuciłby następnie wartość zwracaną na poprawny typ - ponieważ było to konieczne w co najmniej niektórych systemach (w tym w tym, którego nauczyłem się C).Jakiś czas później
(void)
dodano obsadę, aby poinformować kompilator (lub, co bardziej prawdopodobnelint
), że „zwracana wartość zfree()
jest celowo ignorowana”, aby uniknąć reklamacji. Ale lepiej byłoby dodać<stdlib.h>
i pozwolić jej deklaracjiextern void free(void *vp);
powiedziećlint
kompilatorowi, że nie ma żadnej wartości do zignorowania.JFTR: W połowie lat 80-tych ICL Perq był pierwotnie oparty na architekturze zorientowanej na słowa, a
char *
adres lokalizacji pamięci był zupełnie inny niż wskaźnik „any_else” w tej samej lokalizacji. Najważniejsze byłochar *malloc()
jakoś zadeklarować ; kluczowe było rzutowanie z niego wyniku na dowolny inny typ wskaźnika. Obsada faktycznie zmieniła liczbę używaną przez procesor. (Wielką radość sprawiło również uaktualnienie pamięci głównej w naszych systemach z 1 MiB do 2 MiB - ponieważ jądro używało około 3/4 MiB, oznaczało to, że programy użytkownika mogły używać 1 1/4 MiB przed stronicowaniem itp.)źródło
free()
na p. 177, który domyślnie zwracaint
.void
został dodany do niektórych systemów (być może Unix System III) przed wydaniem standardu, ale nie było to częścią C, kiedy napisano K&R 1st Edn (1978). Funkcja, która nie zwróciła wartości, została zadeklarowana bez typu zwracanego (co oznaczało, że została zwróconaint
) i dopóki nie użyłeś wartości, która nie została zwrócona, nie było problemu. Norma C90 musiała traktować ten rodzaj kodu jako prawidłowy - nie udałoby mu się to normalnie, gdyby nie był. Ale C99 usunął zasady „niejawnejint
” i „niejawnej deklaracji funkcji”. Nie cały kod na świecie nadrobił zaległości.(void)
obsadyprintf()
?Ta obsada nie jest potrzebna. Prawdopodobnie nie byłby w tym czasie, ponieważ C został znormalizowany w postaci C89.
Gdyby tak było, wynikałoby to z domniemanej deklaracji . Zazwyczaj oznaczało to, że osoba pisząca kod zapomniała
#include <stdlib.h>
i użyto analizatora statycznego. To nie jest najlepsze obejście i o wiele lepszym pomysłem byłoby właśnie#include <stdlib.h>
zamiast tego. Oto kilka sformułowań z C89 na temat niejawnej deklaracji:Ale to dziwne, ponieważ nie rzutują
malloc
żadnego z nichmalloc
ifree
znajdują się w tym samym pliku nagłówkowym.Możliwe jest również, że jest to tylko błąd lub jakiś sposób poinformowania czytelnika, że
free
nie zwraca żadnego wyniku.źródło
free
ale nie namalloc
.