Pracuję na starym kodzie i prawie każde wywołanie free () używa rzutowania na swoim argumencie. Na przykład,
free((float *)velocity);
free((float *)acceleration);
free((char *)label);
gdzie każdy wskaźnik jest odpowiedniego (i pasującego) typu. Nie widzę w tym sensu. To bardzo stary kod, więc zastanawiam się, czy to kwestia K&R. Jeśli tak, to faktycznie chciałbym wspierać stare kompilatory, które tego wymagały, więc nie chcę ich usuwać.
Czy istnieje techniczny powód, aby używać tych odlewów? Nie widzę nawet pragmatycznego powodu, aby ich używać. Jaki jest sens przypominania sobie o typie danych tuż przed ich zwolnieniem?
EDYCJA: To pytanie nie jest powtórzeniem drugiego pytania. Drugie pytanie to szczególny przypadek tego pytania, co moim zdaniem jest oczywiste, gdyby bliscy wyborcy przeczytali wszystkie odpowiedzi.
Kolofon: Daję „const odpowiedź” znacznik wyboru, ponieważ jest to prawdziwy prawdziwy powód, dla którego może być to konieczne; Jednak odpowiedź o tym, że jest to niestandardowa wersja przed ANSI C (przynajmniej wśród niektórych programistów) wydaje się być powodem, dla którego został użyty w moim przypadku. Wiele osób tutaj ma dobre strony. Dziękuję za Twój wkład.
void*
wcześniejszej wersji C, ale tylkochar*
. Więc jeśli twoje odkrycia archeologiczne ujawnią kod rzucający parametr na free (), uważam, że musi to być albo z tego okresu, albo napisany przez stworzenie z tego czasu. Nie mogę znaleźć dla tego żadnego źródła, więc powstrzymam się od odpowiedzi.Odpowiedzi:
Rzutowanie może być wymagane w celu rozwiązania ostrzeżeń kompilatora, jeśli wskaźniki są
const
. Oto przykład kodu, który powoduje ostrzeżenie bez rzutowania argumentu free:Kompilator (gcc 4.8.3) mówi:
Jeśli używasz
free((float*) velocity);
kompilatora, przestań narzekać.źródło
float*
przed zwolnieniem. Próbowałemfree((void *)velocity);
z gcc 4.8.3. Oczywiście to nie zadziała ze starożytnym kompilatoremconst char *p
jako argument, a następnie uwalnia ją, poprawna rzeczą do zrobienia jest nie do obsadyp
abychar*
przed wywołaniem darmo. Przede wszystkim nie należy go deklarować jako zajmującyconst char *p
, ponieważ modyfikuje*p
i powinien zostać odpowiednio zadeklarowany. (A jeśli przyjmuje wskaźnik const zamiast wskaźnika do const,int *const p
nie musisz rzucać, ponieważ jest to faktycznie legalne i działa dobrze bez rzutowania.)Wcześniejszy standard C miał nie
void*
tylkochar*
, więc trzeba było rzutować wszystkie przekazane parametry. Jeśli natkniesz się na starożytny kod C, możesz znaleźć takie odlewy.Podobne pytanie z referencjami .
Kiedy pierwszy standard C został wydany, prototypy dla malloc i za darmo zmieniły się z konieczności
char*
na tevoid*
, które mają do dziś.I oczywiście w standardowym C takie odlewy są zbędne i po prostu szkodzą czytelności.
źródło
free
na ten sam typ, który już jest?free
rzutowania parametru działają w standardzie C (nie trzeba rzutować). Nie czytałem pierwszej edycji, więc nie mogę powiedzieć, czy byli zdezorientowani również w czasach przedstandardowych lat 80.void*
, ale nie miał też prototypów funkcji, więc rzutowanie argumentu offree
było nadal niepotrzebne nawet w K&R (zakładając, że wszystkie typy wskaźników danych używały tej samej reprezentacji).char *
. Jaki sens miałoby to w starszych kompilatorach bezvoid
? Co osiągnęłyby takie rzuty?Oto przykład, w którym free nie powiedzie się bez obsady:
W C możesz otrzymać ostrzeżenie (otrzymałeś je w VS2012). W C ++ pojawi się błąd.
Pomijając rzadkie przypadki, odlewanie po prostu nadyma kod ...
Edycja: rzuciłem, aby
void*
nieint*
pokazywać niepowodzenia. Będzie działać tak samo, jakint*
zostanie przekonwertowany navoid*
niejawnie. Dodanoint*
kod.źródło
void *
, ale dofloat *
ichar *
. Te odlewy są nie tylko obce, są złe.free(p)
nie udało? Czy dałoby to błąd kompilatora?const
oczywiście wskaźników do kwalifikacji.volatile
istnieje od czasu, gdy C został znormalizowany, jeśli nie dłużej. To było nie dodawać w C99.Stary powód: 1. Używając
free((sometype*) ptr)
, kod jasno określa typ wskaźnika, który powinien być traktowany jako częśćfree()
wywołania. Jawne rzutowanie jest przydatne, gdyfree()
jest zastępowane przez (zrób to sam)DIY_free()
.A
DIY_free()
był (jest) sposobem, szczególnie w trybie debugowania, na wykonanie analizy zwalnianego wskaźnika w czasie wykonywania. Często łączy się toDIY_malloc()
z dodaniem danych uwierzytelniających , globalnych liczników użycia pamięci itp. Moja grupa stosowała tę technikę przez lata, zanim pojawiły się bardziej nowoczesne narzędzia. To zobowiązało, że przedmiot, który ma zostać uwolniony, został rzucony do typu, który został pierwotnie przydzielony.Nowoczesne: unikanie
const
ivolatile
ostrzeżenia zgodnie z odpowiedziami Manosa Nikolaidisa @ i @egur . Myśl Chciałbym zwrócić uwagę na skutki 3 kwalifikatorów :const
,volatile
, irestrict
.[edit] Dodano
char * restrict *rp2
za @R .. komentarzuźródło
restrict
nie jest problemem tylko ze względu na to, gdzie jest umieszczony - wpływa na obiekt, arp
nie na wskazany typ. Gdybyś zamiast tego miałchar *restrict *rp
, miałoby to znaczenie.Oto kolejna alternatywna hipoteza.
Powiedziano nam, że program został napisany przed C89, co oznacza, że nie może pracować nad jakimś rodzajem niezgodności z prototypem
free
, ponieważ nie tylko nie było czegoś takiego jak C89const
anivoid *
przed C89, nie było czegoś takiego jak prototyp funkcji przed C89.stdlib.h
sam w sobie był wymysłem komitetu. Gdyby nagłówki systemowefree
w ogóle zadeklarowały , zrobiłyby to w ten sposób:Teraz kluczową kwestią jest to, że brak prototypów funkcji oznaczał, że kompilator nie sprawdzał typów argumentów . Zastosował domyślne promocje argumentów (te same, które nadal mają zastosowanie do wywołań funkcji wariadycznych) i to wszystko. Odpowiedzialność za ułożenie argumentów na każdej stronie telefonicznej zgodnie z oczekiwaniami odbiorcy spoczywa całkowicie na programiście.
Jednak to nadal nie oznacza, że konieczne było rzucenie argumentu
free
na większość kompilatorów K&R. Funkcja taka jakpowinien zostać poprawnie skompilowany. Myślę więc, że mamy tutaj program napisany, aby radzić sobie z błędnym kompilatorem w nietypowym środowisku: na przykład środowisko, w którym
sizeof(float *) > sizeof(int)
i kompilator nie odpowiedniej konwencji wywoływania wskaźników, chyba że rzucisz je w punkcie wezwania.Nie znam takiego środowiska, ale to nie znaczy, że takiego nie było. Najbardziej prawdopodobnymi kandydatami, którzy przychodzą na myśl, są ograniczone kompilatory „malutkiego C” dla 8- i 16-bitowych mikrometrów we wczesnych latach 80. Nie zdziwiłbym się również, gdyby dowiedział się, że wczesni Crays mieli takie problemy.
źródło
free przyjmuje tylko wskaźniki inne niż const jako parametr. Tak więc w przypadku wskaźników stałych wymagane jest jawne rzutowanie na wskaźnik inny niż stały.
Nie można zwolnić wskaźników stałych w C
źródło