In dieser Frage schlug jemand in einem Kommentar vor, dass ich das Ergebnis von nicht besetzen sollte malloc
, dh
int *sieve = malloc(sizeof(int) * length);
eher, als:
int *sieve = (int *) malloc(sizeof(int) * length);
Warum sollte das so sein?
NULL
. (Das ist wahrscheinlich der Grund, warum C ++ eingeführt wurdenullptr
: C ++ erlaubt keine impliziten Zeigerumwandlungen)Antworten:
Nein ; Sie geben das Ergebnis nicht aus, da:
void *
Dies ist nicht erforderlich, da in diesem Fall automatisch und sicher auf einen anderen Zeigertyp hochgestuft wird.<stdlib.h>
. Dies kann dazu führen , Abstürze (oder, schlimmer noch, nicht zu einem Absturz bis Weg führt später in einem völlig anderen Teil des Codes). Überlegen Sie, was passiert, wenn Zeiger und Ganzzahlen unterschiedlich groß sind. Dann verstecken Sie eine Warnung durch Casting und verlieren möglicherweise Teile Ihrer zurückgegebenen Adresse. Hinweis: Ab C99 sind implizite Funktionen von C verschwunden, und dieser Punkt ist nicht mehr relevant, da nicht automatisch davon ausgegangen wird, dass nicht deklarierte Funktionen zurückgegeben werdenint
.Als Klarstellung, dass Notiz sagte ich , „du nicht werfen“, nicht „Sie nicht brauchen , um cast“. Meiner Meinung nach ist es ein Fehler, die Besetzung einzubeziehen, selbst wenn Sie es richtig verstanden haben. Dies hat einfach keine Vorteile, aber eine Reihe potenzieller Risiken und die Einbeziehung der Besetzung weisen darauf hin, dass Sie die Risiken nicht kennen.
Beachten Sie auch, wie Kommentatoren hervorheben, dass in den obigen Abschnitten nur C und nicht C ++ behandelt wird. Ich glaube fest an C und C ++ als getrennte Sprachen.
Um weiter hinzuzufügen, wiederholt Ihr Code unnötigerweise die Typinformationen (
int
), die Fehler verursachen können. Es ist besser, den Zeiger, der zum Speichern des Rückgabewerts verwendet wird, zu de-referenzieren, um die beiden zusammen zu "sperren":Dadurch wird auch die
length
nach vorne verschoben, um die Sichtbarkeit zu verbessern, und die redundanten Klammern werden mitsizeof
gelöscht. Sie werden nur benötigt, wenn das Argument ein Typname ist. Viele Leute scheinen dies nicht zu wissen (oder zu ignorieren), was ihren Code ausführlicher macht. Denken Sie daran:sizeof
ist keine Funktion! :) :)Während das Bewegen
length
nach vorne in einigen seltenen Fällen die Sichtbarkeit erhöhen kann , sollte man auch darauf achten, dass es im allgemeinen Fall besser sein sollte, den Ausdruck wie folgt zu schreiben:Da die
sizeof
erste beibehalten wird , wird in diesem Fall sichergestellt, dass die Multiplikation mindestens mitsize_t
Mathematik erfolgt.Vergleichen:
malloc(sizeof *sieve * length * width)
gegenmalloc(length * width * sizeof *sieve)
die Sekunde kann daslength * width
Wann überlaufenwidth
undlength
sind kleinere Typen alssize_t
.quelle
int x = (int) 12;
nur, um die Dinge klar zu machen?(int)12
ist nicht vergleichbar.12
ist eineint
, die Besetzung macht einfach nichts. Das Retval vonmalloc()
istvoid *
nicht der Zeigertyp , in den gegossen wurde. (Wenn es nicht istvoid *
. Also wäre die Analogie zu dem(int)12
,(void*)malloc(…)
worüber niemand spricht.)In C müssen Sie den Rückgabewert von nicht umwandeln
malloc
. Der von zurückgegebene Zeiger auf voidmalloc
wird automatisch in den richtigen Typ konvertiert. Wenn Sie jedoch möchten, dass Ihr Code mit einem C ++ - Compiler kompiliert wird, ist eine Umwandlung erforderlich. Eine bevorzugte Alternative in der Community ist die Verwendung der folgenden Optionen:Dies befreit Sie außerdem davon, dass Sie sich Sorgen machen müssen, die rechte Seite des Ausdrucks zu ändern, wenn Sie jemals den Typ ändern
sieve
.Casts sind schlecht, wie die Leute betont haben. Besonders Zeigerabdrücke.
quelle
malloc(length * sizeof *sieve)
dass es so aussieht, als wäresizeof
es eine Variable - also denke ich, dassmalloc(length * sizeof(*sieve))
es besser lesbar ist.malloc(length * (sizeof *sieve))
noch lesbarer. MEINER BESCHEIDENEN MEINUNG NACH.()
Problem beiseite, beachten Sie, dass Ihre vorgeschlagene Art der Bestellung eingeschaltet. Wichtige Überlegungen bei Elementzählwert wie berechnet wirdlength*width
, die haltensizeof
wird zuerst in diesem Fall versichert die Multiplikation mit mindestens getansize_t
math. Vergleichemalloc(sizeof( *ptr) * length * width)
vs.malloc(length * width * sizeof (*ptr))
- der 2. kann überlaufen,length*width
wennwidth,length
kleinere Typen das sindsize_t
.malloc(sizeof *sieve * length)
static_cast>()
(oderreinterpret_cast<>()
) ist mit keinem Dialekt von C. kompatibelSie haben werfen, denn:
type *
Vergleich zutype **
.#include
eine entsprechende Header-Datei nicht gefunden haben, verfehlt den Wald für die Bäume . Es ist dasselbe wie zu sagen: "Mach dir keine Sorgen darüber, dass du den Compiler nicht gebeten hast, dich darüber zu beschweren, dass du keine Prototypen siehst - diese lästige stdlib.h ist die WIRKLICH wichtige Sache, an die du dich erinnern musst!"malloc()
Bugs bei einer Besetzung viel schneller erkannt werden. Wie bei Behauptungen verringern Anmerkungen, die Absichten aufdecken, Fehler.quelle
.c
/.cpp
-Datei zum Kompilieren als beides zu haben, ist nicht sehr oft nützlich, aber ein Fall ist das Hinzufügen von C ++ -throw
Unterstützung beim Kompilieren mit dem C ++ - Compiler (aberreturn -1;
beim Kompilieren mit dem C-Compiler oder was auch immer).malloc
Aufruf verwenden:char **foo = malloc(3*sizeof(*foo));
wenn ganz sicher: 3 Zeiger auf Zeichenzeiger. dann Schleife und tunfoo[i] = calloc(101, sizeof(*(foo[i])));
. Ordnen Sie ein Array mit 101 Zeichen zu, das sauber auf Nullen initialisiert ist. Keine Besetzung erforderlich. Ändern Sie die Erklärung inunsigned char
oder einen anderen Typ, und Sie sind immer noch gutstruct Zebra *p; ... p=malloc(sizeof struct Zebra);
dessen kann das Malloc nicht vermeiden, Informationen über den Typ von p zu duplizieren, aber weder der Compiler noch die Überprüfung des lokalen Codes würden ein Problem erkennen, wenn sich ein Typ ändert, der andere jedoch nicht. Ändern Sie den Code inp=(struct Zebra*)malloc(sizeof struct Zebra);
und der Compiler wird kreischen, wenn der Besetzungstyp nicht übereinstimmtp
, und die lokale Inspektion wird zeigen ...Wie bereits erwähnt, wird es nicht für C, sondern für C ++ benötigt. Wenn Sie glauben, dass Sie Ihren C-Code aus irgendeinem Grund mit einem C ++ - Compiler kompilieren möchten, können Sie stattdessen ein Makro verwenden, z.
Auf diese Weise können Sie es immer noch sehr kompakt schreiben:
und es wird für C und C ++ kompiliert.
quelle
new
in der Definition von C ++?new
, müssen Sie verwenden,delete
und wenn Sie verwendenmalloc()
, müssen Sie verwendenfree()
. Mischen Sie sie niemals.NEW
ist das Aufrufen des Makros wahrscheinlich eine schlechte Idee, da die Ressource niemals mitdelete
(oderDELETE
) zurückgegeben wird, sodass Sie Ihren Wortschatz mischen. Stattdessen wäre es sinnvoller , es zu benennenMALLOC
, oder besser gesagtCALLOC
in diesem Fall.Aus der Wikipedia :
Obwohl Malloc ohne Casting die bevorzugte Methode ist und die meisten erfahrenen Programmierer sie wählen , sollten Sie verwenden, was immer Sie möchten, um sich der Probleme bewusst zu sein.
dh: Wenn Sie ein C-Programm als C ++ kompilieren müssen (obwohl es eine separate Sprache ist), müssen Sie das Ergebnis der Verwendung umwandeln
malloc
.quelle
malloc()
Aufruf entfernt deklariert ist "? Könnten Sie ein Beispiel geben?p = malloc(sizeof(*p) * count)
Redewendung Änderungen des Typs automatisch aufnimmt, sodass Sie keine Warnungen erhalten und nichts ändern müssen. Dies ist also kein wirklicher Vorteil gegenüber der besten Alternative für das Nicht-Casting.In C können Sie einen
void
Zeiger implizit in eine andere Art von Zeiger konvertieren , sodass eine Umwandlung nicht erforderlich ist. Die Verwendung eines kann dem gelegentlichen Beobachter nahe legen, dass es einen Grund gibt, warum einer benötigt wird, der irreführend sein kann.quelle
Sie setzen das Ergebnis von malloc nicht um, da dies Ihrem Code sinnlose Unordnung verleiht.
Der häufigste Grund, warum Menschen das Ergebnis von Malloc wirken, ist, dass sie sich nicht sicher sind, wie die C-Sprache funktioniert. Das ist ein Warnzeichen: Wenn Sie nicht wissen , wie eine bestimmte Sprache Mechanismus funktioniert, dann nicht zu erraten. Schlagen Sie nach oder fragen Sie nach Stapelüberlauf.
Einige Kommentare:
Ein ungültiger Zeiger kann ohne explizite Umwandlung in / von einem anderen Zeigertyp konvertiert werden (C11 6.3.2.3 und 6.5.16.1).
C ++ erlaubt jedoch keine implizite Umwandlung zwischen
void*
und einem anderen Zeigertyp. In C ++ wäre die Besetzung also korrekt gewesen. Wenn Sie jedoch in C ++ programmieren, sollten Sienew
malloc () verwenden und nicht. 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 versehen, da sie nicht kompatibel sind.
Wenn ein C-Compiler keine Funktion finden kann, weil Sie vergessen haben, den Header einzuschließen, wird diesbezüglich ein Compiler- / Linker-Fehler angezeigt. Wenn Sie also vergessen haben
<stdlib.h>
, dies einzuschließen, können Sie Ihr Programm nicht erstellen.Bei alten Compilern, die einer Version des Standards folgen, die älter als 25 Jahre ist, würde das Vergessen der Einbeziehung
<stdlib.h>
zu gefährlichem Verhalten führen. Denn in diesem alten Standard haben Funktionen ohne sichtbaren Prototyp den Rückgabetyp implizit in konvertiertint
. Das explizite Casting des Ergebnisses von malloc würde diesen Fehler dann verbergen.Aber das ist wirklich kein Problem. Sie verwenden keinen 25 Jahre alten Computer. Warum sollten Sie also einen 25 Jahre alten Compiler verwenden?
quelle
In C erhalten Sie eine implizite Konvertierung von
void *
einem beliebigen anderen (Daten-) Zeiger.quelle
Das Umwandeln des von zurückgegebenen Werts
malloc()
ist jetzt nicht erforderlich, aber ich möchte einen Punkt hinzufügen, auf den anscheinend niemand hingewiesen hat:In den alten Tagen, dh bevor ANSI C
void *
den generischen Zeigertyp bereitstellt ,char *
ist dies der Typ für eine solche Verwendung. In diesem Fall kann der Cast die Compiler-Warnungen herunterfahren.Referenz: C FAQ
quelle
Wenn ich nur meine Erfahrung hinzufüge und Computertechnik studiere, sehe ich, dass die zwei oder drei Professoren, die ich in C geschrieben habe, immer Malloc besetzten, aber derjenige, den ich fragte (mit einem immensen Lebenslauf und Verständnis von C), sagte mir, dass es absolut unnötig ist, aber war früher nur absolut spezifisch und brachte die Schüler in die Mentalität, absolut spezifisch zu sein. Im Wesentlichen ändert das Casting nichts an der Funktionsweise, es macht genau das, was es sagt, weist Speicher zu, und das Casting wirkt sich nicht darauf aus, Sie erhalten denselben Speicher, und selbst wenn Sie ihn versehentlich in etwas anderes umwandeln (und dem Compiler irgendwie ausweichen) Fehler) C greift auf die gleiche Weise darauf zu.
Bearbeiten: Casting hat einen bestimmten Punkt. Wenn Sie die Array-Notation verwenden, muss der generierte Code wissen, wie viele Speicherplätze er vorrücken muss, um den Anfang des nächsten Elements zu erreichen. Dies wird durch Casting erreicht. Auf diese Weise wissen Sie, dass Sie für ein Double 8 Bytes voraus sind, während Sie für ein Int 4 Bytes voraus sind, und so weiter. Daher hat es keine Auswirkung, wenn Sie die Zeigernotation verwenden. In der Array-Notation wird dies erforderlich.
quelle
p = malloc(sizeof *p * n);
ist dies jedoch so einfach und besser.Es ist nicht zwingend erforderlich, die Ergebnisse von zu übertragen
malloc
, da sie zurückgegebenvoid*
werden und avoid*
auf einen beliebigen Datentyp verweisen kann.quelle
Ein void-Zeiger ist ein generischer Objektzeiger, und C unterstützt die implizite Konvertierung von einem void-Zeigertyp in andere Typen, sodass keine explizite Typumwandlung erforderlich ist.
Wenn Sie jedoch möchten, dass derselbe Code auf einer C ++ - Plattform, die keine implizite Konvertierung unterstützt, perfekt kompatibel ist, müssen Sie die Typumwandlung durchführen, sodass alles von der Benutzerfreundlichkeit abhängt.
quelle
malloc
und Freunden in C ++ ist ein gutes Warnsignal dafür, dass es besondere Aufmerksamkeit verdient (oder in C neu geschrieben wird).void *
und reicht dahervoid *
nicht aus, um einen Funktionszeiger gut zu speichern.Dies ist, was das Referenzhandbuch für die GNU C-Bibliothek sagt:
Und tatsächlich sagt der ISO C11-Standard (S. 347) Folgendes:
quelle
Der zurückgegebene Typ ist void *, der in den gewünschten Datenzeigertyp umgewandelt werden kann, um dereferenzierbar zu sein.
quelle
void*
kann auf den gewünschten Typ umgewandelt werden, dies ist jedoch nicht erforderlich, da es automatisch konvertiert wird. Die Besetzung ist also nicht notwendig und aus den in den Antworten mit hoher Punktzahl genannten Gründen in der Tat unerwünscht.In der Sprache C kann jedem Zeiger ein ungültiger Zeiger zugewiesen werden, weshalb Sie keine Typumwandlung verwenden sollten. Wenn Sie eine "typsichere" Zuordnung wünschen, kann ich die folgenden Makrofunktionen empfehlen, die ich in meinen C-Projekten immer verwende:
Mit diesen können Sie einfach sagen
Für nicht dynamische Arrays ist das dritte unverzichtbare Funktionsmakro
Das macht Array-Schleifen sicherer und bequemer:
quelle
malloc()
.void*
zu / von einem Funktionszeiger kann Informationen verlieren, so dass "in jedem Fall ein ungültiger Zeiger einem beliebigen Zeiger zugewiesen werden kann" ein Problem darstellt. Das Zuweisen einesvoid*
, vonmalloc()
zu einem beliebigen Objektzeiger ist jedoch kein Problem.do
Schleifenkommentar bezog sich auf Makros, die eine Schleife beinhalten, die sich jedoch von der Titelfrage entfernt. Diesen Kommentar entfernen. Werde diesen auch später runter nehmen.Dies hängt von der Programmiersprache und dem Compiler ab. Wenn Sie
malloc
in C verwenden, müssen Sie cast nicht eingeben, da cast automatisch eingegeben wird. Wenn Sie jedoch C ++ verwenden, sollten Sie cast eingeben, damalloc
einvoid*
Typ zurückgegeben wird.quelle
Menschen, die an GCC und Clang gewöhnt sind, werden verwöhnt. Es ist nicht so gut da draußen.
Ich war über die Jahre ziemlich entsetzt über die erstaunlich alten Compiler, die ich verwenden musste. Oft verfolgen Unternehmen und Manager einen äußerst konservativen Ansatz beim Ändern von Compilern und testen nicht einmal , ob ein neuer Compiler (mit besserer Einhaltung von Standards und Codeoptimierung) in ihrem System funktioniert. Die praktische Realität für arbeitende Entwickler ist, dass Sie beim Codieren Ihre Basen abdecken müssen und das Casting von Mallocs leider eine gute Angewohnheit ist, wenn Sie nicht steuern können, welcher Compiler auf Ihren Code angewendet werden kann.
Ich würde auch vorschlagen , dass viele Organisationen einen Codierungsstandard ihrer eigenen Anwendung und das sollten die Methode Menschen sein folgen , wenn sie definiert ist. In Ermangelung einer expliziten Anleitung tendiere ich dazu, am ehesten überall zu kompilieren, anstatt mich sklavisch an einen Standard zu halten.
Das Argument, dass es nach aktuellen Standards nicht notwendig ist, ist durchaus gültig. Dieses Argument lässt jedoch die praktischen Aspekte der realen Welt aus. Wir codieren nicht in einer Welt, die ausschließlich vom Standard des Tages bestimmt wird, sondern von den praktischen Aspekten dessen, was ich gerne als "Realitätsfeld des lokalen Managements" bezeichne. Und das ist mehr verbogen und verdreht als jemals zuvor. :-)
YMMV.
Ich neige dazu, Malloc als Verteidigungsoperation zu betrachten. Nicht schön, nicht perfekt, aber im Allgemeinen sicher. (Ehrlich gesagt, wenn Sie stdlib.h nicht aufgenommen haben, haben Sie weit mehr Probleme als das Casting von Malloc!).
quelle
Ich habe die Besetzung nur eingefügt, um die Missbilligung des hässlichen Lochs im Typsystem zu zeigen, wodurch Code wie das folgende Snippet ohne Diagnose kompiliert werden kann, obwohl keine Besetzungen verwendet werden, um die schlechte Konvertierung herbeizuführen:
Ich wünschte, das gäbe es nicht (und es gibt es nicht in C ++) und so habe ich gegossen. Es repräsentiert meinen Geschmack und meine Programmierpolitik. Ich werfe nicht nur einen Zeiger, sondern effektiv einen Stimmzettel und treibe Dämonen der Dummheit aus . Wenn ich Dummheit nicht wirklich austreiben kann , dann lassen Sie mich zumindest den Wunsch mit einer Geste des Protests zum Ausdruck bringen.
In der Tat ist es eine gute Praxis,
malloc
(und Freunde) mit Funktionen zu versehen, die zurückkehrenunsigned char *
, und im Grunde nievoid *
in Ihrem Code zu verwenden. Wenn Sie einen generischen Zeiger auf ein beliebiges Objekt benötigen, verwenden Sie einchar *
oderunsigned char *
und haben Casts in beide Richtungen. Die einzige Entspannung, die man sich vielleicht gönnen kann, ist die Verwendung von Funktionen wiememset
undmemcpy
ohne Abgüsse.Zum Thema Gießen und C ++ Kompatibilität, wenn Sie Ihren Code schreiben , so dass es kompiliert , da beide C und C ++ (in diesem Fall Sie haben den Rückgabewert zu werfen ,
malloc
wenn es um etwas anderes als die Zuordnungvoid *
), können Sie ein sehr hilfreichen tun Sache für sich selbst: Sie können Makros für das Casting verwenden, die beim Kompilieren als C ++ in Casts im C ++ - Stil übersetzt werden, beim Kompilieren als C ++ jedoch auf einen C-Cast reduzieren:Wenn Sie sich an diese Makros halten,
grep
zeigt Ihnen eine einfache Suche in Ihrer Codebasis nach diesen Bezeichnern, wo sich alle Ihre Besetzungen befinden, sodass Sie überprüfen können, ob sie falsch sind.Wenn Sie dann in Zukunft den Code regelmäßig mit C ++ kompilieren, wird die Verwendung einer geeigneten Besetzung erzwungen. Wenn Sie beispielsweise
strip_qual
nur einconst
oder entfernenvolatile
, das Programm sich jedoch so ändert, dass jetzt eine Typkonvertierung durchgeführt wird, erhalten Sie eine Diagnose, und Sie müssen eine Kombination von Casts verwenden, um die gewünschte Konvertierung zu erhalten.Um Ihnen bei der Einhaltung dieser Makros zu helfen, verfügt der GNU C ++ (nicht C!) - Compiler über eine schöne Funktion: eine optionale Diagnose, die für alle Vorkommen von C-Casts erstellt wird.
Wenn Ihr C-Code als C ++ kompiliert wird, können Sie mit dieser
-Wold-style-cast
Option alle Vorkommen der(type)
Casting-Syntax ermitteln, die sich möglicherweise in den Code eingeschlichen haben, und diese Diagnose weiterverfolgen, indem Sie sie durch eine geeignete Auswahl aus den oben genannten Makros (oder a) ersetzen Kombination, falls erforderlich).Diese Behandlung von Konvertierungen ist die größte eigenständige technische Rechtfertigung für die Arbeit in einem "sauberen C": der kombinierte C- und C ++ - Dialekt, der wiederum das Casting des Rückgabewerts von technisch rechtfertigt
malloc
.quelle
Das Beste, was Sie tun können, wenn Sie in C programmieren, wann immer dies möglich ist:
-Wall
und beheben Sie alle Fehler und Warnungenauto
-Wall
und-std=c++11
. Beheben Sie alle Fehler und Warnungen.Mit diesem Verfahren können Sie die strikte C ++ - Typprüfung nutzen und so die Anzahl der Fehler reduzieren. Insbesondere zwingt Sie dieses Verfahren zum Einbeziehen
stdlib.h
, sonst erhalten Sieund zwingt Sie auch, das Ergebnis von zu werfen,
malloc
oder Sie werden erhaltenoder was auch immer Ihr Zieltyp ist.
Die einzigen Vorteile des Schreibens in C anstelle von C ++, die ich finden kann, sind
Beachten Sie, dass die zweiten Nachteile im Idealfall verschwinden sollten, wenn Sie die für C gemeinsame Teilmenge zusammen mit dem statischen polymorphen Merkmal verwenden.
Für diejenigen, die strenge C ++ - Regeln als unpraktisch empfinden, können wir die C ++ 11-Funktion mit abgeleitetem Typ verwenden
quelle
gcc -c c_code.c
), die C ++ Code als C ++ (zBg++ -c cpp_code.cpp
), und dann verbinden sie zusammen (zBgcc c_code.o cpp_code.o
oder umgekehrt, abhängig von den Projektabhängigkeiten). Jetzt sollte es keinen Grund geben, sich jeglicher netter Merkmale beider Sprachen zu berauben ...p = malloc(sizeof(*p));
, was beip
Änderungen an einem anderen Typnamen überhaupt nicht geändert werden muss. Der vorgeschlagene "Vorteil" des Castings besteht darin, dass Sie einen Kompilierungsfehler erhalten, wennp
der falsche Typ vorliegt , aber es ist noch besser, wenn er einfach funktioniert.Nein, Sie geben das Ergebnis von nicht aus
malloc()
.Im Allgemeinen gießen
void *
Sie nicht zu oder von .Ein typischer Grund dafür ist, dass ein Versäumnis
#include <stdlib.h>
unbemerkt bleiben kann. Dies ist seit langem kein Problem mehr, da C99 implizite Funktionsdeklarationen illegal gemacht hat. Wenn Ihr Compiler also mindestens C99 entspricht, erhalten Sie eine Diagnosemeldung.Es gibt jedoch einen viel stärkeren Grund, keine unnötigen Zeigerwürfe einzuführen:
In C ist eine Zeigerumwandlung fast immer ein Fehler . Dies liegt an der folgenden Regel ( §6.5 S. 7 in N1570, dem neuesten Entwurf für C11):
Dies wird auch als strikte Aliasing-Regel bezeichnet . Der folgende Code ist also undefiniertes Verhalten :
Und manchmal überraschend ist auch Folgendes:
Manchmal Sie tun müssen , um gegossene Zeiger, aber die gegebene strenge Aliasing - Regel , müssen Sie damit sehr vorsichtig sein. Jedes Auftreten eines Zeigers in Ihrem Code ist ein Ort, an dem Sie seine Gültigkeit überprüfen müssen . Daher schreiben Sie niemals eine unnötige Zeigerumwandlung.
tl; dr
Kurz gesagt: Da in C jedes Auftreten einer Zeigerumwandlung eine rote Fahne für Code auslösen sollte, der besondere Aufmerksamkeit erfordert, sollten Sie niemals unnötige Zeigerumwandlungen schreiben .
Randnotizen:
Es gibt Fälle, in denen Sie tatsächlich eine Besetzung benötigen
void *
, z. B. wenn Sie einen Zeiger drucken möchten:Die Besetzung ist hier notwendig, da
printf()
es sich um eine variable Funktion handelt, sodass implizite Konvertierungen nicht funktionieren.In C ++ ist die Situation anders. Das Umwandeln von Zeigertypen ist beim Umgang mit Objekten abgeleiteter Klassen etwas üblich (und korrekt). Daher macht es Sinn , dass in C ++, die Umwandlung in und aus
void *
ist nicht implizit. C ++ bietet eine ganze Reihe verschiedener Casting-Varianten.quelle
Ich mache die Besetzung lieber, aber nicht manuell. Mein Favorit ist die Verwendung von
g_new
undg_new0
Makros von glib. Wenn glib nicht verwendet wird, würde ich ähnliche Makros hinzufügen. Diese Makros reduzieren die Codeduplizierung, ohne die Typensicherheit zu beeinträchtigen. Wenn Sie den Typ falsch verstehen, erhalten Sie eine implizite Umwandlung zwischen nicht ungültigen Zeigern, die eine Warnung verursachen würde (Fehler in C ++). Wenn Sie vergessen, den Header einzuschließen, derg_new
und definiertg_new0
, wird eine Fehlermeldung angezeigt.g_new
undg_new0
beide nehmen die gleichen Argumente, im Gegensatz dazumalloc
weniger Argumente alscalloc
. Fügen Sie einfach hinzu0
, um den mit Null initialisierten Speicher zu erhalten. Der Code kann ohne Änderungen mit einem C ++ - Compiler kompiliert werden.quelle
Casting ist nur für C ++ und nicht für C. Wenn Sie einen C ++ - Compiler verwenden, sollten Sie ihn besser in C-Compiler ändern.
quelle
Das Konzept hinter dem Void-Zeiger besteht darin, dass er in jeden Datentyp umgewandelt werden kann, weshalb malloc void zurückgibt. Außerdem müssen Sie sich der automatischen Typumwandlung bewusst sein. Es ist also nicht zwingend erforderlich, den Zeiger umzuwandeln, obwohl Sie dies tun müssen. Es hilft dabei, den Code sauber zu halten und das Debuggen
quelle
Ein ungültiger Zeiger ist ein generischer Zeiger, und C unterstützt die implizite Konvertierung von einem ungültigen Zeigertyp in andere Typen, sodass keine explizite Typumwandlung erforderlich ist.
Wenn Sie jedoch möchten, dass derselbe Code auf einer C ++ - Plattform, die keine implizite Konvertierung unterstützt, perfekt kompatibel ist, müssen Sie die Typumwandlung durchführen, sodass alles von der Benutzerfreundlichkeit abhängt.
quelle
Wie bereits erwähnt, wird es nicht für C, sondern für C ++ benötigt.
Durch das Einschließen der Besetzung kann ein C-Programm oder eine C-Funktion möglicherweise als C ++ kompiliert werden.
In C ist dies nicht erforderlich, da void * automatisch und sicher auf einen anderen Zeigertyp hochgestuft wird.
Wenn Sie dann einen Cast ausführen, kann dies einen Fehler verbergen, wenn Sie vergessen haben, stdlib.h einzuschließen . Dies kann zu Abstürzen führen (oder, schlimmer noch, erst viel später in einem völlig anderen Teil des Codes zu einem Absturz führen).
Da stdlib.h den Prototyp für malloc enthält, wird gefunden. In Ermangelung eines Prototyps für malloc verlangt der Standard, dass der C-Compiler davon ausgeht, dass malloc ein int zurückgibt. Wenn keine Umwandlung vorliegt, wird eine Warnung ausgegeben, wenn diese Ganzzahl dem Zeiger zugewiesen wird. Bei der Besetzung wird diese Warnung jedoch nicht ausgegeben, wodurch ein Fehler ausgeblendet wird.
quelle
Das Casting von Malloc ist in C nicht erforderlich, in C ++ jedoch obligatorisch.
Casting ist in C nicht erforderlich, weil:
void *
wird im Fall von C automatisch und sicher auf einen anderen Zeigertyp hochgestuft.<stdlib.h>
. Dies kann zu Abstürzen führen.malloc
aufgerufen und umgewandelt wird.Andererseits kann Casting die Portabilität Ihres Programms erhöhen. Das heißt, es ermöglicht einem C-Programm oder einer C-Funktion, als C ++ zu kompilieren.
quelle
Für mich ist das Mitnehmen und die Schlussfolgerung hier, dass das Casting
malloc
in C absolut NICHT notwendig ist, aber wenn Sie jedoch Casting durchführen, hat dies keine Auswirkungen,malloc
damalloc
Ihnen immer noch Ihr gewünschter gesegneter Speicherplatz zugewiesen wird. Ein weiterer Grund zum Mitnehmen ist der Grund oder einer der Gründe, warum Benutzer Casting durchführen. Dadurch können sie dasselbe Programm entweder in C oder C ++ kompilieren.Es mag andere Gründe geben, aber andere Gründe würden Sie mit ziemlicher Sicherheit früher oder später in ernsthafte Schwierigkeiten bringen.
quelle
Sie können, müssen aber nicht in C umwandeln. Sie müssen umwandeln, wenn dieser Code als C ++ kompiliert ist.
quelle