W C, dlaczego niektórzy ludzie rzucają wskaźnik przed uwolnieniem go?

Pracuję na starej bazie kodu i prawie każde wywołanie funkcji free() używa cast na swoim argumencie. Na przykład,

free((float *)velocity);
free((float *)acceleration);
free((char *)label);

Gdzie każdy wskaźnik jest typu odpowiadającego (i pasującego). Nie widzę w tym sensu. To bardzo stary kod, więc zastanawiam się, czy to coś z K&R. Jeśli tak, to chcę wspierać stare Kompilatory, które mogły tego wymagać, więc nie chcę ich usuwać.

Czy Jest jakiś techniczny powód, aby używać tych odlewów? I don ' t even see to bardzo pragmatyczny powód, by ich używać. Po co przypominać sobie o typie danych tuż przed jego uwolnieniem?

EDIT: to pytanie jest Nie duplikatem drugiego pytania. Inne pytanie jest szczególnym przypadkiem tego pytania, które moim zdaniem jest oczywiste, jeśli bliscy wyborcy przeczytaliby wszystkie odpowiedzi.

Colophon: daję "const answer" zaznaczenie, ponieważ jest to bonafide prawdziwy powód, dla którego może to być konieczne, jednak odpowiedź na to jako pre-ANSI C custom (przynajmniej wśród niektórych programistów) wydaje się być powodem, dla którego został użyty w moim przypadku. Wiele dobrych punktów przez wielu ludzi tutaj. Dziękuję za wkład.

Author: PLNech, 2015-12-01

6 answers

Casting może być wymagany do rozwiązania ostrzeżeń kompilatora, jeśli wskaźniki są const. Oto przykład kodu, który powoduje Ostrzeżenie bez rzucania argumentu free:

const float* velocity = malloc(2*sizeof(float));
free(velocity);

A kompilator (gcc 4.8.3) mówi:

main.c: In function ‘main’:
main.c:9:5: warning: passing argument 1 of ‘free’ discards ‘const’ qualifier from pointer target type [enabled by default]
     free(velocity);
     ^
In file included from main.c:2:0:
/usr/include/stdlib.h:482:13: note: expected ‘void *’ but argument is of type ‘const float *’
 extern void free (void *__ptr) __THROW;

Jeśli używasz free((float*) velocity); kompilator przestaje narzekać.

 168
Author: Manos Nikolaidis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-01 19:17:23

Pre-standard C nie miał void*, ale tylko char* , więc trzeba było oddać wszystkie parametry przekazane. Jeśli natkniesz się na starożytny kod C, możesz więc znaleźć takie odlewy.

Podobne pytanie z referencjami .

Kiedy pierwszy standard C został wydany, prototypy dla malloc i free zmieniły się z char* na void*, które mają do dziś.

I oczywiście w standardzie C, takie odlewy są zbędne i szkodzą czytelności.

 59
Author: Lundin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:56

Oto przykład, w którym free zawiedzie bez obsady:

volatile int* p = (volatile int*)malloc(5 * sizeof(int));
free(p);        // fail: warning C4090: 'function' : different 'volatile' qualifiers
free((int*)p);  // success :)
free((void*)p); // success :)

W C możesz otrzymać ostrzeżenie (dostałem je w VS2012). W C++ pojawi się błąd.

Pomijając rzadkie przypadki, casting po prostu wydmuchuje kod...

Edit: Rzuciłem do void*, a nie int*, aby demaskować porażkę. Będzie działać tak samo, jak int* zostanie przekonwertowane do void* domyślnie. Dodano kod {[2] }.

 33
Author: egur,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-01 15:44:54

Stary powód: 1. Używając free((sometype*) ptr), Kod jest jawny co do typu, który wskaźnik powinien być rozpatrywany jako część wywołania free(). Jawna obsada jest przydatna, gdy free() jest zastąpiona (zrób to sam) DIY_free().

#define free(ptr) DIY_free(ptr, sizeof (*ptr))

A DIY_free() był (jest) sposobem, szczególnie w trybie debugowania, do wykonywania analizy czasu pracy zwalnianego wskaźnika. Jest to często sparowane z DIY_malloc(), aby dodać sententials, globalne zużycie pamięci itp. Moja grupa używała tej techniki przez lata, zanim pojawiły się bardziej nowoczesne narzędzia. Zobowiązał on, że przedmiot, który jest wolny, został oddany do rodzaju jest pierwotnie przydzielony.

    Biorąc pod uwagę wiele godzin spędzonych na śledzeniu problemów z pamięcią itp., małe sztuczki, takie jak casting typu free ' d pomogłyby w wyszukiwaniu i zawężaniu debugowania.

Nowoczesne: unikanie const i volatile ostrzeżeń adresowanych przez Manos Nikolaidis@ i @ egur. Pomyślałem, że zwrócę uwagę na efekty 3 kwalifikatorów: const, volatile, oraz restrict.

[edytuj] dodano char * restrict *rp2 na @R.. komentarz

void free_test(const char *cp, volatile char *vp, char * restrict rp, 
    char * restrict *rp2) {
  free(cp);  // warning
  free(vp);  // warning
  free(rp);  // OK
  free(rp2);  // warning
}

int main(void) {
  free_test(0,0,0,0);
  return 0;
}
 30
Author: chux,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:29:29

Oto inna hipoteza alternatywna.

Powiedziano nam, że program został napisany przed C89, co oznacza, że nie może obejść pewnego rodzaju niedopasowania do prototypu free, ponieważ nie tylko nie było czegoś takiego jak const ani void * przed C89, nie było czegoś takiego jak prototyp funkcji przed C89. Sam był wynalazkiem Komitetu. Gdyby nagłówki systemowe w ogóle deklarowały free, zrobiłyby to tak to:

extern free();  /* no `void` return type either! */

Najważniejsze jest to, że brak prototypów funkcji oznaczał, że kompilator nie sprawdzał typu argumentu. Zastosował domyślny argument promotions (ten sam, który nadal stosuje się do zmiennych wywołań funkcji) i to wszystko. Odpowiedzialnosc za wyslanie argumentow na kazdej stronie callee zgodnie z oczekiwaniami callee nalezy w calosci do programisty.

Jednak to nadal nie znaczy, że trzeba było oddać argument do free na większości kompilatorów K & R. Funkcja jak

free_stuff(a, b, c)
    float *a;
    char *b;
    int *c;
{
    free(a);
    free(b);
    free(c);
}

Powinny być poprawnie skompilowane. Myślę więc, że to, co mamy tutaj, to program napisany do radzenia sobie z błędnym kompilatorem dla nietypowego środowiska: na przykład środowisko, w którym sizeof(float *) > sizeof(int) i kompilator nie używaliby odpowiedniej konwencji wywołania wskaźników, chyba że rzucisz je w punkcie wywołania.

Nie znam takiego środowiska, ale to nie znaczy, że go nie było. Najbardziej prawdopodobnymi kandydatami, które przychodzą na myśl, są wycięte" malutkie kompilatory C " dla 8-i 16-bitowych mikrosów na początku lat 80. nie zdziwiłbym się też, gdyby wczesne Craysy miały takie problemy.
 15
Author: zwol,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-12-11 02:55:23

Free przyjmuje jako parametr tylko wskaźniki non-const. Tak więc w przypadku wskaźników const wymagane jest jawne rzucanie na wskaźnik non-const.

Unable to free const pointers in C

 9
Author: Nobody,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:55:16