Frage Werfe ich das Ergebnis von malloc?


Im diese Fragejemand vorgeschlagen in einem Kommentar das sollte ich nicht Wirf das Ergebnis von malloc, d.h.

int *sieve = malloc(sizeof(int) * length);

eher, als:

int *sieve = (int *) malloc(sizeof(int) * length);

Warum sollte das der Fall sein?


2039
2018-03-03 10:13


Ursprung


Antworten:


Nein; Sie nicht Wirf das Ergebnis, denn:

  • Es ist unnötig, als void * wird in diesem Fall automatisch und sicher auf jeden anderen Zeigertyp heraufgestuft.
  • Es fügt dem Code Unordnung hinzu, Umwandlungen sind nicht sehr einfach zu lesen (besonders wenn der Zeigertyp lang ist).
  • Es lässt dich dich wiederholen, was im Allgemeinen schlecht ist.
  • Es kann einen Fehler verbergen, wenn Sie vergessen haben, einzuschließen <stdlib.h>. Dies kann zu Abstürzen führen nicht verursachen einen Absturz bis viel später in einem völlig anderen Teil des Codes). Überlegen Sie, was passiert, wenn Zeiger und Ganzzahlen unterschiedlich groß sind; dann versteckst du eine Warnung durch das Casting und kannst Teile deiner zurückgegebenen Adresse verlieren. Anmerkung: Ab C11 sind implizite Funktionen aus C verschwunden, und dieser Punkt ist nicht mehr relevant, da keine automatische Annahme besteht, dass nicht deklarierte Funktionen zurückkehren int.

Zur Klarstellung, beachte, dass ich sagte "Du machst nicht", nicht "du nicht" brauchen "Ich denke, es ist ein Versäumnis, die Besetzung aufzunehmen, auch wenn Sie es richtig gemacht haben. Es gibt einfach keine Vorteile, aber eine Reihe potenzieller Risiken, einschließlich der Besetzung, zeigt an, dass Sie es nicht wissen über die Risiken.

Beachten Sie auch, wie die Kommentatoren darauf hinweisen, dass das oben Gesagte gerade C und nicht C ++ betrifft. Ich glaube fest an C und C ++ als separate Sprachen.

Um weiter hinzuzufügen, wiederholt Ihr Code unnötigerweise die Typinformation (int) was zu Fehlern führen kann. Es ist besser, den Zeiger, der zum Speichern des Rückgabewerts verwendet wird, zu dereferenzieren, um die beiden zusammen zu "sperren":

int *sieve = malloc(length * sizeof *sieve);

Dies bewegt auch die length nach vorne für erhöhte Sichtbarkeit und löscht die überflüssigen Klammern mit sizeof; Sie werden nur benötigt wenn das Argument ein Typname ist. Viele Leute scheinen dies nicht zu wissen (oder zu ignorieren), was ihren Code verständlicher macht. Merken: sizeof ist keine Funktion! :)


Während der Bewegung length Nach vorne kann in seltenen Fällen die Sichtbarkeit erhöhen, sollte man auch darauf achten, dass es im allgemeinen Fall besser ist, den Ausdruck wie folgt zu schreiben:

int *sieve = malloc(sizeof *sieve * length);

Seit dem halten sizeof zuerst wird in diesem Fall sichergestellt, dass die Multiplikation mit mindestens durchgeführt wird size_t Mathematik.

Vergleichen: malloc(sizeof *sieve * length * width) gegen malloc(length * width * sizeof *sieve) der zweite kann überlaufen length * width wann width und length sind kleinere Typen als size_t.


1915
2018-03-03 10:17



In C müssen Sie den Rückgabewert von nicht umsetzen malloc. Der Zeiger auf void wurde von zurückgegeben malloc wird automatisch in den richtigen Typ konvertiert. Wenn Sie möchten, dass Ihr Code mit einem C ++ - Compiler kompiliert wird, ist jedoch eine Umwandlung erforderlich. Eine bevorzugte Alternative in der Community ist die Verwendung der folgenden:

int *sieve = malloc(sizeof *sieve * length);

Dadurch müssen Sie sich auch nicht mehr darum kümmern, die rechte Seite des Ausdrucks zu ändern, wenn Sie den Typ ändern sieve.

Abgüsse sind schlecht, wie die Leute darauf hingewiesen haben. Speziell Zeiger wirft.


327
2018-03-03 10:17



Sie machen werfen, weil:

  • Es macht deinen Code tragbarer Zwischen C und C ++, und wie SO-Erfahrung zeigt, behaupten sehr viele Programmierer, dass sie in C schreiben, wenn sie wirklich in C ++ schreiben (oder C plus lokale Compiler-Erweiterungen).
  • Versäumnis dies zu tun kann einen Fehler verbergen: Notieren Sie alle SO-Beispiele für Verwirrung beim Schreiben type * gegen type **.
  • Die Vorstellung, dass es dich davon abhält, dich zu bemerken, scheiterte #include eine entsprechende Header-Datei fehlt der Wald für die Bäume. Es ist das gleiche wie zu sagen: "Mach dir keine Sorgen darüber, dass du es versäumt hast, den Compiler zu bitten, sich darüber zu beschweren, dass du keine Prototypen siehst - dieses nervtötende stdlib.h ist das ECHTE wichtige, an das du dich erinnern musst!"
  • Es zwingt ein zusätzlicher kognitiver Gegencheck. Es stellt den (angeblichen) gewünschten Typ direkt neben die Arithmetik, die Sie für die rohe Größe dieser Variable tun. Ich wette, du könntest eine SO-Studie machen, die das zeigt malloc() Fehler werden viel schneller gefangen, wenn es einen Cast gibt. Wie bei Behauptungen verringern Anmerkungen, die Absicht aufzeigen, Fehler.
  • Sich selbst so zu wiederholen, dass die Maschine prüfen kann, ist oft ein groß Idee. In der Tat ist das eine Behauptung, und diese Verwendung von Besetzung ist eine Behauptung. Behauptungen sind immer noch die allgemeinste Technik, die wir haben, um den Code korrekt zu machen, da Turing vor so vielen Jahren auf diese Idee gekommen ist.

291
2018-02-14 16:15



Wie bereits erwähnt, wird es nicht für C, sondern für C ++ benötigt. Wenn Sie meinen, dass Sie Ihren C-Code mit einem C ++ - Compiler kompilieren möchten, können Sie aus welchen Gründen auch immer ein Makro verwenden, wie zum Beispiel:

#ifdef __cplusplus
# define NEW(type, count) ((type *)calloc(count, sizeof(type)))
#else
# define NEW(type, count) (calloc(count, sizeof(type)))
#endif

So können Sie es immer noch sehr kompakt schreiben:

int *sieve = NEW(int, 1);

und es wird für C und C ++ kompilieren.


148
2018-03-03 11:17



Von dem Wikipedia

Vorteile beim Gießen

  • Durch das Einbeziehen der Umwandlung kann ein C-Programm oder eine C-Funktion möglicherweise als C ++ kompiliert werden.

  • Der Cast ermöglicht Versionen von malloc vor 1989, die ursprünglich ein char * zurückgegeben haben.

  • Casting kann dem Entwickler helfen, Inkonsistenzen in der Typisierung zu erkennen, sollte sich der Ziel-Zeigertyp ändern, insbesondere wenn der Zeiger weit vom Aufruf malloc () entfernt deklariert wird (obwohl moderne Compiler und statische Analysatoren auf ein solches Verhalten warnen können, ohne dass der Cast erforderlich ist).

Nachteile beim Gießen

  • Gemäß dem ANSI C-Standard ist die Besetzung redundant.

  • Das Hinzufügen des Cast kann den Maskenfehler bei der Aufnahme des Headers enthalten stdlib.h, im   welcher der Prototyp für malloc gefunden wird. In Abwesenheit von a   Prototyp für Malloc, der Standard erfordert, dass der C-Compiler   Angenommen, malloc gibt einen int zurück. Wenn es keine Besetzung gibt, ist eine Warnung   ausgegeben, wenn diese Ganzzahl dem Zeiger zugewiesen ist; jedoch mit   die Besetzung, diese Warnung wird nicht erzeugt und versteckt einen Fehler. Auf bestimmte   Architekturen und Datenmodelle (wie LP64 auf 64-Bit-Systemen, wo   long und Zeiger sind 64-Bit und int ist 32-Bit), dieser Fehler kann   tatsächlich zu undefiniertem Verhalten, wie es implizit deklariert wird   malloc gibt einen 32-Bit-Wert zurück, während die tatsächlich definierte Funktion   Gibt einen 64-Bit-Wert zurück. Abhängig von Aufrufkonventionen und Speicher   Layout, dies kann dazu führen, dass Stack-Smashing. Dieses Problem ist weniger wahrscheinlich   in modernen Compilern unbemerkt bleiben, wie sie einheitlich produzieren   Warnungen, dass eine nicht deklarierte Funktion verwendet wurde, so wird eine Warnung angezeigt   immer noch erscheinen. Das Standardverhalten von GCC ist z. B. das Anzeigen von a   Warnung, die "inkompatible implizite Deklaration von Built-in liest   Funktion "unabhängig davon, ob der Cast vorhanden ist oder nicht.

  • Wenn der Typ des Zeigers bei seiner Deklaration geändert wird, kann man   Außerdem müssen alle Zeilen geändert werden, in denen malloc aufgerufen und umgewandelt wird.

Obwohl Malloc ohne Casting ist die bevorzugte Methode und die erfahrensten Programmierer wählen siesollten Sie das verwenden, was Ihnen am besten gefällt.

Wenn Sie C-Programm als C ++ kompilieren müssen (obwohl das eine separate Sprache ist), sollten Sie verwenden malloc mit Gießen.


95
2017-10-09 21:23



In C können Sie einen Void-Zeiger implizit in einen anderen Pointer-Typ konvertieren, sodass eine Umwandlung nicht erforderlich ist. Die Verwendung eines kann dem zufälligen Beobachter nahelegen, dass es einen Grund gibt, warum man benötigt wird, was irreführend sein kann.


94
2018-03-03 10:18



Sie werfen das Ergebnis von malloc nicht, weil dadurch Ihr Code sinnlos wird.

Der häufigste Grund, warum Menschen das Ergebnis von malloc ausspielen, ist, dass sie sich nicht sicher sind, wie die C-Sprache funktioniert. Das ist ein Warnzeichen: Wenn Sie nicht wissen, wie ein bestimmter Sprachmechanismus funktioniert, dann nicht Raten Sie mal. Schaut es euch an oder fragt nach Stack Overflow.

Einige Kommentare:

  • Ein Void-Zeiger kann ohne explizite Umwandlung in einen anderen Pointer-Typ konvertiert werden (C11 6.3.2.3 und 6.5.16.1).

  • C ++ erlaubt jedoch keine implizite Umwandlung zwischen void* und ein anderer Zeigertyp. In C ++ wäre die Besetzung also korrekt gewesen. Aber wenn Sie in C ++ programmieren, sollten Sie verwenden new und nicht malloc (). Und Sie sollten niemals C-Code mit einem C ++ - Compiler kompilieren.

    Wenn Sie sowohl C als auch C ++ mit demselben Quellcode unterstützen müssen, verwenden Sie Compiler-Schalter, um die Unterschiede zu markieren. Versuchen Sie nicht, beide Sprachstandards mit demselben Code zu sättigen, da sie nicht kompatibel sind.

  • Wenn ein C-Compiler eine Funktion nicht finden kann, weil Sie vergessen haben, den Header einzuschließen, erhalten Sie einen Compiler / Linker-Fehler darüber. Also wenn du vergessen hast einzuschließen <stdlib.h> Das ist kein Problem, Sie können Ihr Programm nicht erstellen.

  • Auf alten Compilern, die einer Version des Standards folgen, die mehr als 25 Jahre alt ist, vergessend zu enthalten <stdlib.h> würde zu gefährlichem Verhalten führen. Weil in diesem uralten Standard Funktionen ohne einen sichtbaren Prototyp den Rückgabetyp implizit umwandelten int. Wenn das Ergebnis von malloc explizit übertragen würde, würde dieser Fehler dann ausgeblendet.

    Aber das ist wirklich kein Thema. Sie benutzen keinen 25 Jahre alten Computer, warum sollten Sie einen 25 Jahre alten Compiler verwenden?


83
2018-03-20 15:53



In C erhalten Sie eine implizite Konvertierung von void* zu irgendeinem anderen (Daten) Zeiger.


82
2018-03-03 10:16