
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?
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.
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.
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.
9862800cookie-checkWarum benötigt C++ eine Umwandlung für malloc(), C aber nicht?yes
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)
nichtsizeof(int*)
. Das heißt, es ist noch besser zu verwendensizeof *int_ptr
was garantiert, dass Sie für jeden Typ die richtige Menge an Speicher zuweisenint_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*
odermalloc()
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