Warum den Rückgabewert von free auf void setzen?

82

Ich lese ein Buch ( Programmieren mit POSIX-Threads von Butenhof, 1997), das C verwendet, und bin auf die folgende Zeile gestoßen:

(void)free(data);

Hier dataist nur ein Zeiger auf eine zugewiesene Struktur,

data = malloc(sizeof(my_struct_t));

Warum ist das Ergebnis der freeBesetzung void?

Nach meinem Verständnis von C scheint dies aus zwei Gründen keinen Sinn zu ergeben:

  • Die freie Funktion kehrt bereits zurück void
  • Der Code verwendet nicht den Rückgabewert (er wird nicht einmal einer Variablen zugewiesen).

Das Buch wurde 1997 geschrieben. Ist das eine Art Vermächtnis?

Der Autor erwähnt, dass die Beispiele unter Digital Unix 4.0d ausgeführt wurden, aber ich kann mir immer noch keinen Grund vorstellen, das Ergebnis einer Funktion jemals umzuwandeln, wenn Sie dieses Ergebnis nicht verwenden.

Adam Johnston
quelle
Einige mögliche Erklärungen finden Sie hier: stackoverflow.com/questions/689677/…
Timbo
3
Wann ist aus Neugier das Datum der Veröffentlichung Ihres C-Buches? (Um welches Buch handelt es sich?) Wenn es vor etwa 1995 liegt, könnte es eine Rechtfertigung dafür geben - Standard-C-Compiler waren bis dahin nicht allgegenwärtig. Wenn es danach veröffentlicht wird und immer noch die Besetzung enthält (und keine Erklärung dafür, warum), machen Sie sich Sorgen darüber, welche anderen schlechten Gewohnheiten es Ihnen beibringt. Holen Sie sich ein neueres Buch!
Jonathan Leffler
10
Sieht aus wie Programmieren mit POSIX-Threads
Eugene Sh.
3
@ JonathanLeffler Wie in meinem ursprünglichen Beitrag erwähnt, wurde das Buch 1997 veröffentlicht und verwendete UNIX 4.0d. Das Buch ist "Programmieren mit POSIX-Threads" von David R. Butenhof. Bisher war es sehr informativ und wurde von einem der ursprünglichen Mitwirkenden am POSIX-Thread-Standard geschrieben.
Adam Johnston
6
Ich habe meine Kopie davon in der letzten Woche verwendet - ja, es ist immer noch nützlich. Es wurde an der Schwelle des "allgegenwärtigen Standards C" geschrieben (ich sagte "ungefähr 1995"). Das 'UNIX 4.0d' klingt wie Digital UNIX - dort hat Butenhof gearbeitet, und das Vorwort erwähnt es. Behandeln Sie die Besetzung free()als eine Kuriosität in dem Buch, die Sie nicht emulieren müssen. Es war vor langer Zeit halb relevant, aber es ist nicht mehr relevant.
Jonathan Leffler

Antworten:

100

Wenn wir über die Standardfunktion sprechen, freedann ist ihr Prototyp

void free(void *ptr);

Daher ist die Besetzung völlig nutzlos.
Nun einige Spekulationen.

Der Autor hat möglicherweise vergessen, den stdlib.hHeader einzuschließen, der diesen Prototyp deklariert, sodass der Compiler den Rückgabetyp als annimmt int. Während der statischen Analyse dieses Codes warnte der Compiler nun vor dem nicht verwendeten Rückgabewert dessen, was er für eine Nichtfunktion hält void. Solche Warnungen werden normalerweise durch Hinzufügen der Besetzung zu zum Schweigen gebracht void.

Eugene Sh.
quelle
50
Beachten Sie jedoch, dass es falsch ist, die Warnung zum Schweigen zu bringen, wenn die Besetzung aus dem spekulierten Grund eingeführt wurde . In diesem Fall weist der Compiler einen anderen Typ zu freeals tatsächlich, mit dem Ergebnis, dass der Aufruf ein undefiniertes Verhalten aufweist (vorausgesetzt, die C90-Semantik, bei der das Aufrufen einer nicht deklarierten Funktion nicht in allen Fällen von Natur aus UB aufweist). In der Praxis ist es plausibel, dass dies auf einigen Systemen zu einem echten Fehlverhalten führen würde. Die richtige Lösung besteht darin, eine korrekte Deklaration für die Funktion bereitzustellen.
John Bollinger
11
Insbesondere enthalten die Beispiele in "Programmieren mit POSIX-Threads" wiederholt nicht die relevanten Standardheader. Vielleicht war dies eine schlechte Praxis des Autors, sie hätten ein nicht standardmäßiges Compiler-Setup verwenden können, das standardmäßig alle Standardbibliotheken enthielt.
Lundin
74

Es wäre eine Legacy-Sache!

Bevor es einen C-Standard gab, wäre die free()Funktion (implizit) vom Typ gewesen int- da es noch keinen verlässlichen Typ voidfür die Rückgabe gab. Es wurde kein Wert zurückgegeben.

Als der Code zum ersten Mal für die Verwendung mit Standard-C-Compilern geändert wurde, war er wahrscheinlich nicht enthalten <stdlib.h>(da er vor dem Standard nicht vorhanden war). Alter Code würde extern char *malloc();(möglicherweise ohne extern) für die Zuordnungsfunktionen schreiben ( ähnlich für calloc()und realloc()) und musste nicht deklariert werden free(). Und der Code würde dann den Rückgabewert auf den richtigen Typ umwandeln - da dies zumindest auf einigen Systemen erforderlich war (einschließlich dem, auf dem ich C gelernt habe).

Einige Zeit später wurde die (void)Besetzung hinzugefügt, um dem Compiler (oder wahrscheinlicher lint) mitzuteilen, dass "der Rückgabewert von free()absichtlich ignoriert wird", um eine Beschwerde zu vermeiden. Es wäre jedoch besser gewesen, die <stdlib.h>Deklaration hinzuzufügen und dem Compiler extern void free(void *vp);mitzuteilen, lintdass kein Wert zu ignorieren ist.

JFTR: Mitte der 80er Jahre befand sich der ICL Perq ursprünglich in einer wortorientierten Architektur, und die char *Adresse für einen Speicherort war eine ganz andere Zahl als der Zeiger "any_else" auf denselben Speicherort. Es war entscheidend, char *malloc()irgendwie zu erklären ; Es war entscheidend, das Ergebnis daraus auf einen anderen Zeigertyp zu übertragen. Die Besetzung hat tatsächlich die von der CPU verwendete Nummer geändert. (Es gab auch viel Freude, als der Hauptspeicher auf unseren Systemen von 1 MiB auf 2 MiB aktualisiert wurde - da der Kernel ungefähr 3/4 MiB verwendete, bedeutete dies, dass Benutzerprogramme 1 1/4 MiB vor dem Paging usw. verwenden konnten.)

Jonathan Leffler
quelle
9
Ich habe gerade eine Kopie von K & R, 1. Ausgabe, geöffnet, die eine Implementierung von free()auf S. 22 enthält . 177, die implizit zurückgibt int.
Ex Nihilo
9
Natürlich - voidwurde einigen Systemen (vielleicht Unix System III) hinzugefügt, bevor der Standard veröffentlicht wurde, aber das war nicht Teil von C, als K & R 1st Edn (1978) geschrieben wurde. Eine Funktion, die keinen Wert zurückgegeben hat, wurde ohne Rückgabetyp deklariert (was bedeutet, dass sie zurückgegeben wurde int). Solange Sie den nicht zurückgegebenen Wert nicht verwendet haben, gab es kein Problem. Der C90-Standard musste diese Art von Code als gültig behandeln - er wäre düster gescheitert, wie es ein Standard nicht getan hätte. C99 entfernte jedoch die intRegeln für "implizite " und "implizite Funktionsdeklaration". Nicht der gesamte Code der Welt hat aufgeholt.
Jonathan Leffler
5
Op behauptet, das Buch sei 1997 geschrieben worden. Sie sprechen hier von einem sehr frühen "K & R C" vor dem Standard, und es ist unwahrscheinlich, dass irgendjemand überhaupt ein Buch darüber schreiben würde. Das einzige derartige Buch, das meines Wissens existierte, war in der Tat die 1. Auflage von K & R.
Lundin
Es war eine häufige (wenn auch quixotische) Praxis, keine Header einzuschließen, wenn Sie dachten, Sie könnten mit einer impliziten Deklaration davonkommen, weil die Leute dachten, dies würde die Erstellungszeiten verkürzen.
Spencer
Verwendet jemand eine (void)Besetzung für printf()?
Luis Colorado
11

Diese Besetzung wird nicht benötigt. Es wäre wahrscheinlich nicht zu der Zeit gewesen, als C in Form von C89 standardisiert worden war.

Wenn es gewesen wäre, wäre es auf eine implizite Erklärung zurückzuführen . Dies bedeutete normalerweise, dass die Person, die den Code schrieb, vergaß #include <stdlib.h>und ein statischer Analysator verwendet wurde. Dies ist nicht die beste Problemumgehung, und eine viel bessere Idee wäre gewesen, nur #include <stdlib.h>stattdessen. Hier einige Formulierungen aus C89 zur impliziten Deklaration:

Wenn der Ausdruck, der in einem Funktionsaufruf vor der Liste der in Klammern gesetzten Argumente steht, nur aus einem Bezeichner besteht und für diesen Bezeichner keine Deklaration sichtbar ist, wird der Bezeichner implizit genau so deklariert, als ob im innersten Block, der den Funktionsaufruf enthält, die Deklaration

extern int identifier();

erschien.

Aber das ist seltsam, weil sie nicht das Ergebnis von mallocbeidem übertragen mallocund freesich in derselben Header-Datei befinden.

Es ist auch möglich, dass dies nur ein Fehler oder eine Möglichkeit ist, dem Leser mitzuteilen, dass freekein Ergebnis zurückgegeben wird.

SS Anne
quelle
5
Nur weil eine Sprache standardisiert wird, bedeutet dies nicht, dass jeder seine Toolchain und seinen Code sofort aktualisiert, um sie anzupassen. Es ist plausibel, dass "K & R" C im alten Stil noch etwa 8 Jahre geblieben ist. Trotzdem stimme ich zu, dass es seltsam ist, dass ein statisches Analysewerkzeug eine Besetzung erfordert, freeaber nicht für malloc.
dan04
4
@ dan04 Normalerweise verwendest du das Ergebnis von malloc;) Ich bin kein Fan davon, Dinge wie (void) printf (...) zu schreiben, um zu verhindern, dass der Compiler Warnungen ausspuckt, aber "muss ohne Warnungen kompilieren, auch die dummen" ist etwas, das passiert in vielen Projekten.
Richard