Warum benötigt C++ eine Umwandlung für malloc(), C aber nicht?

Lesezeit: 6 Minuten

Warum benotigt C eine Umwandlung fur malloc C aber nicht
bodacydo

Ich war schon immer neugierig darauf – warum muss ich in C++ den Rückgabewert umwandeln? malloc aber nicht in C?

Hier ist das Beispiel in C++, das funktioniert:

int *int_ptr = (int *)malloc(sizeof(int*));

Und hier ist das Beispiel in C++, das nicht funktioniert (kein Cast):

int *int_ptr = malloc(sizeof(int*));

Ich habe gehört, dass in C tatsächlich eine Ausgabe gecastet wird malloc() ist ein Fehler.

Kann sich jemand zu diesem Thema äußern?

  • Da C++ typempfindlicher ist, müssen Sie den genauen Typ über eine Umwandlung angeben.

    – Abhai

    13. August 2010 um 14:30 Uhr

  • Dies steht nicht in direktem Zusammenhang mit Ihrer Frage, aber ich denke, Sie möchten sizeof(int)nicht sizeof(int*). Das heißt, es ist noch besser zu verwenden sizeof *int_ptrwas garantiert, dass Sie für jeden Typ die richtige Menge an Speicher zuweisen int_ptr zufällig darauf hinzuweisen.

    – bkat

    13. August 2010 um 14:31 Uhr

  • Warum sollten Sie malloc in C++ verwenden?

    – Seifenkiste

    13. August 2010 um 14:31 Uhr

  • In C ist die Besetzung nicht falsch, aber völlig unnötig. In C++ mit void* oder malloc() denn alles (außer der Verwendung einer für C entworfenen Schnittstelle) ist mit ziemlicher Sicherheit ein Fehler.

    – Mike Seymour

    13. August 2010 um 15:02 Uhr


  • @R .. geh und lerne D oder Go oder so

    – Quonux

    14. Juli 2013 um 20:20 Uhr

Mehrere Punkte:

C erlaubt die implizite Konvertierung von void-Zeigern in jeden anderen Objektzeigertyp. C++ nicht.

Casting das Ergebnis von malloc() in C wird eine nützliche Diagnose unterdrücken, wenn Sie vergessen, stdlib.h einzuschließen oder anderweitig keine Deklaration für haben malloc() im Visier. Denken Sie daran, dass C, wenn es einen Funktionsaufruf ohne vorherige Deklaration sieht, davon ausgeht, dass die Funktion zurückkehrt int. Wenn Sie keine Erklärung für haben malloc() und Sie lassen die Umwandlung weg, erhalten Sie eine Diagnose, die besagt, dass Sie versuchen, inkompatible Typen (int to pointer) zuzuweisen. Wenn Sie das Ergebnis umwandeln, unterdrücken Sie die Diagnose und haben möglicherweise Laufzeitprobleme, da nicht garantiert ist, dass die Konvertierung eines Zeigerwerts in ein int und wieder zurück in einen Zeiger zu einem nützlichen Ergebnis führt.

Wenn Sie C++ schreiben, sollten Sie verwenden new und delete anstatt malloc() und free(). Ja, ja, ja, ich habe alle Gründe gehört, warum Leute wollen, dass ihr Code sowohl als C als auch als C++ kompiliert wird, aber die Vorteile der Verwendung des richtigen Speicherverwaltungstools für die Sprache überwiegen meiner Meinung nach die Kosten für die Wartung von zwei Versionen.

Beachten Sie das void * Typ wurde im C89-Standard hinzugefügt; frühere Versionen von C hatten malloc() Rückkehr char *also in diesen Versionen die Besetzung war erforderlich, wenn Sie das Ergebnis einem anderen Zeigertyp zuweisen. Fast jeder unterstützt jedoch mindestens den C89-Standard, sodass die Wahrscheinlichkeit, dass Sie auf eine dieser älteren Implementierungen stoßen, sehr, sehr gering ist.

  • Gibt kein moderner Compiler unabhängig von Casting-Problemen eine Warnung für eine fehlende Deklaration von malloc() aus?

    – Daniel Stützbach

    13. August 2010 um 15:01 Uhr

  • @Daniel: Das hängt auch von deiner Warnstufe ab. Eine Cast-Warnung wird normalerweise in einer niedrigeren Warnstufe angezeigt als eine fehlende Deklaration.

    – mmx

    13. August 2010 um 15:36 Uhr

  • Vielleicht, aber es ist immer noch am besten, den Verband wegzulassen.

    – Johannes Bode

    13. August 2010 um 15:43 Uhr

Das liegt daran, dass C++ eine stark typisierte Sprache ist. In C++ sind implizite Casts nur erlaubt, wenn sie “erweitern”, dh wenn der neue Typ jeden Wert aufnehmen kann, den der alte Typ aufnehmen kann. Das Casting von einem kleineren Integer-Typ zu einem größeren Integer-Typ ist erlaubt; Casting von jedem Zeigertyp auf void* ist erlaubt; Casting von einer Unterklasse in ihre Oberklasse ist erlaubt. Alle anderen Umwandlungen müssen explizit vorgenommen werden, wodurch dem Compiler mitgeteilt wird: “Ich weiß, was ich tue, das ist kein Fehler”.

malloc() gibt a zurück void*, was alles sein kann, sodass der Compiler nicht garantieren kann, dass Ihre Umwandlung erfolgreich (oder sinnvoll) ist. Indem Sie eine explizite Umwandlung verwenden, teilen Sie dem Compiler mit, dass das, was Sie tun, tatsächlich beabsichtigt ist.

C, OTOH, hat keine so starren Wurfregeln; Sie können problemlos zwischen zwei beliebigen Typen wechseln, und Sie als Programmierer sind dafür verantwortlich, dass keine schlimmen Dinge als Folge passieren.

  • Ich kann implizit ein werfen int zu bool ohne Probleme.

    – Onkel Bens

    13. August 2010 um 16:54 Uhr

  • „Das liegt daran, dass C++ eine stark typisierte Sprache ist.“ … und C nicht!?

    – CDhowie

    12. April 2017 um 15:56 Uhr

  • C++ ist eine stark typisierte Sprache.” Eh. “Stark typisiert” ist als Begriff ziemlich bedeutungslos. Autoren verwenden ihn im Allgemeinen für “Ich mag diese Sprache”. “In C++ sind implizite Casts nur erlaubt, wenn sie “erweitern”, dh wenn der neue Typ jeden Wert aufnehmen kann, den der alte Typ aufnehmen kann.” Mehrere Probleme damit: Ein “cast” ist eine explizite Typumwandlung; wenn es implizit ist, ist es kein Cast. C++ erlaubt das Einschränken von Typumwandlungen, genau wie C: int i = 1.3; float f = ULONG_MAX; kompiliert ohne Fehler. Konvertieren Derived* zu Base* ist wegen Arrays unsicher. C++ erlaubt es, C nicht.

    – Melpomen

    17. September 2018 um 7:45 Uhr

  • [In C] Sie können problemlos zwischen zwei beliebigen Typen wechseln” Nicht wahr, z. B. können Sie nicht in einen Strukturtyp konvertieren (weder explizit (durch Casting) noch implizit).

    – Melpomen

    17. September 2018 um 7:46 Uhr

C unterstützt die implizite Umwandlung von void* zu anderen Zeigertypen. C++ verbietet es.

Ein Grund, warum es in C verpönt ist, den Rückgabewert von explizit zu casten malloc ist das, wenn die malloc Signatur nicht in der aktuellen Kompilierungseinheit enthalten ist, geht der Compiler davon aus, dass der Rückgabetyp ist int und die implizite Konvertierung in den Zeigertyp, den Sie zuweisen, führt zu einer Kompilierzeitwarnung, die Sie sofort auflösen würden. Wenn Sie diesen Fehler machen, wird bei einer expliziten Besetzung keine Warnung ausgegeben.

C hat sehr lockere Typregeln und C++ hat etwas strengere Regeln. Der Unterschied besteht in diesem Fall darin, dass C eine implizite Konvertierung/Zuweisung zwischen Objektzeigern und erlaubt void Zeiger. C++ nicht.

Tatsächlich förderte C im alten Stil sogar die implizite Konvertierung nach/von void Zeiger, als Teil der generischen C-Programmierung im alten Stil. C++ wurde nie benötigt void Hinweise für solche, da es Funktionsüberladung und Templates etc. gibt void Zeiger in C++ sind oft faul.

In Bezug auf das Schlagen der toten Pferdedebatte über das Gießen des Ergebnisses malloc Fehler verursachen, falls stdlib.h nicht enthalten war, war dies nie gültiges C++ und es war in den letzten 21 Jahren auch kein gültiges C.

Empfohlene Vorgehensweise:

C

  • Wenn Sie mit kompilieren -std=c89, -ansi oder -dinosaur etc, dann nicht werfen.
  • Befolgen Sie andernfalls Ihren Codierungsstandard.
    • Wenn es implizite Konvertierungen zwischen erlaubt void und Objektzeiger, nicht umwandeln.
    • Wenn dies nicht möglich ist, führen Sie eine Umwandlung durch (dies impliziert wahrscheinlich, dass Sie eine statische Codeanalyse verwenden).
    • Wenn Sie keinen Codierungsstandard haben, spielt es wirklich keine Rolle. Die Besetzung ist harmlos, fügt aber Unordnung hinzu.

C++

  • Immer werfen.
  • Vermeiden void Zeiger.
  • Vor allem vermeiden malloc und verwenden new/new[] stattdessen.
986280cookie-checkWarum benötigt C++ eine Umwandlung für malloc(), C aber nicht?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy