Frage

diese Frage , jemand in einem Kommentar , dass ich vorgeschlagen sollte nicht warf das Ergebnis malloc, dh

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

statt:

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

Warum sollte dies der Fall sein?

War es hilfreich?

Lösung

Nein ; Sie nicht das Ergebnis werfen, da:

  • Es ist nicht notwendig, da void * in diesem Fall jeden anderen Zeigertyp automatisch und sicher gefördert wird.
  • Sie fügt hinzu, Unordnung auf den Code, Abgüsse sind nicht sehr leicht zu lesen (vor allem, wenn der Zeiger-Typ ist lang).
  • Es macht man sich wiederholen, was in der Regel schlecht.
  • Es kann ein Fehler verbergen, wenn Sie vergessen haben, <stdlib.h> aufzunehmen. Dies kann dazu führen, Abstürze (oder, schlimmer noch, nicht verursacht einen Absturz bis weit später in einem völlig anderen Teil des Codes). Überlegen Sie, was passiert, wenn Zeiger und Zahlen sind unterschiedlich große; dann sind Sie eine Warnung durch Gießen versteckt und könnten Bits Ihrer zurück Adresse verlieren. . Hinweis: ab C11 impliziter Funktionen von C gegangen sind, und dieser Punkt ist nicht mehr relevant, da gibt es keine automatische Annahme, dass nicht angemeldete Funktionen int zurückkehren

Als Klarstellung, beachten Sie, dass ich sagte: „Sie werfen nicht“, nicht „Sie nicht Notwendigkeit zu werfen“. Meiner Meinung nach ist es ein Versagen der Besetzung aufzunehmen, auch wenn Sie es richtig gemacht haben. Es gibt einfach keine Vorteile, die es zu tun, aber eine Reihe von potenziellen Risiken, einschließlich der Besetzung zeigt an, dass Sie nicht über die Risiken wissen.

Beachten Sie auch, wie Kommentatoren weisen darauf hin, dass die oben spricht über gerade C, C ++ nicht. Ich glaube sehr fest in C und C ++ als separate Sprachen.

weiter hinzuzufügen Code unnötig wiederholt die Typinformationen (int), die zu Fehlern führen können. Es ist besser, den Zeiger dereferenzieren den Rückgabewert zu speichern, verwendet wird, zu „sperren“ die beiden zusammen:

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

Dies bewegt auch den length nach vorne für bessere Sichtbarkeit und fällt die redundanten Klammern mit sizeof; sie werden nur benötigt, , wenn das Argument eine Typname ist. Viele Leute scheinen nicht zu wissen (oder ignorieren) diese, die ihren Code ausführlicher macht. Denken Sie daran: sizeof keine Funktion! :)


Während length nach vorne zu bewegen kann erhöht die Sichtbarkeit in einigen seltenen Fällen soll man auch darauf achten, dass im allgemeinen Fall, sollte es besser sein, den Ausdruck zu schreiben, wie:

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

Da die sizeof hielt ersten, in diesem Fall gewährleistet Multiplikation mit mindestens size_t Mathematik durchgeführt wird.

Vergleichen: malloc(sizeof *sieve * length * width) vs. malloc(length * width * sizeof *sieve) der zweite kann die length * width überlaufen, wenn width und length sind kleinere Arten als size_t

.

Andere Tipps

In C, brauchen Sie nicht den Rückgabewert von malloc zu werfen. Der Zeiger auf void von malloc zurückgegeben wird automatisch auf den richtigen Typ umgewandelt. Wenn Sie jedoch Ihr Code mit einem C ++ Compiler kompiliert werden sollen, wird ein gegossener benötigt. Eine bevorzugte Alternative unter der Gemeinschaft ist folgendes zu verwenden:

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

, die Sie zusätzlich befreit mit etwa Änderung der rechten Seite des Ausdrucks zur Sorge, wenn Sie jemals die Art der sieve ändern.

Casts sind schlecht, wie die Leute haben darauf hingewiesen. Speziell Zeiger Würfe.

Sie Besetzung, denn:

  • Es macht Ihren Code mehr tragbar zwischen C und C ++, und als SO Erfahrung zeigt, sehr viele Programmierer behaupten, dass sie in C schreiben, wenn sie wirklich in C schreiben ++ (oder C plus lokale Compiler Erweiterungen).
  • , dies zu tun Failing kann einen Fehler verbergen : beachten Sie die alle SO Beispiele für verwirrend, wenn type * gegen type ** schreiben
  • .
  • Die Idee, dass es hält Sie bemerken Sie eine entsprechende Header-Datei Misses der Wald für die Bäume #include fehlgeschlagen. Es ist das Gleiche wie die Aussage „nicht über die Tatsache Sorgen Sie den Compiler fragen versäumt zu bemängeln nicht Prototypen zu sehen - das nervtötende stdlib.h die REAL Wichtigste ist, sich zu erinnern“
  • Es zwingt einen zusätzlichen kognitiven Cross-Check . Es setzt die (angeblichen) gewünschten Typ direkt neben dem arithmetischen Sie für die rohe Größe dieser Variablen zu tun. Ich wette, Sie könnten eine SO Studie tun, die zeigt, dass malloc() Fehler viel schneller gefangen werden, wenn es eine Besetzung. Wie bei den Behauptungen, Anmerkungen, die Absicht Abnahme Fehler aufzudecken.
  • Sie sich in einer Art und Weise zu wiederholen, dass die Maschine überprüfen kann, ist oft eine groß Idee. In der Tat ist das, was eine Behauptung ist, und diese Verwendung von Guss ist eine Behauptung. Assertions sind immer noch die allgemeine Technik, die wir für das Erhalten Code richtig haben, da Turing mit der Idee so vor vielen Jahren kam.

Wie andere erwähnt, ist es nicht für C benötigt, sondern auch für C ++. Wenn Sie denken, Sie werden Ihren C-Code mit einem C ++ Compiler kompilieren, aus welchen Gründen immer, ein Makro stattdessen verwenden können, wie:

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

Auf diese Weise können Sie es immer noch schreiben in einem sehr kompakten Art und Weise:

int *sieve = NEW(int, 1);

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

Von der Wikipedia :

  

Vorteile zu Gießen

     
      
  • Einschließlich der Besetzung einem C-Programm oder eine Funktion zu kompilieren, wie C ++.

  • kann zulassen   
  • Die Besetzung ermöglicht vor 1989 Versionen von malloc, die ursprünglich ein Zeichen zurückgegeben *.

  •   
  • Casting kann der Entwickler helfen, die Zielzeiger Typänderung identifizieren Inkonsistenzen in Schlicht sollten, insbesondere dann, wenn der Zeiger deklariert ist weit von der malloc () Aufruf (obwohl moderne Compiler und statische Analysatoren auf ein solches Verhalten warnen können, ohne dass die Besetzung).

  •   
     

Nachteile zu Gießen

     
      
  • Unter dem ANSI-C-Standard, die Besetzung ist überflüssig.

  •   
  • die Besetzung Hinzufügen Ausfall Maske kann den Header stdlib.h schließen, in   der der Prototyp für malloc gefunden. In Abwesenheit eines   Prototyp für malloc verlangt der Standard, dass die C-Compiler   nehmen eine int malloc zurückkehrt. Wenn es keine Besetzung ist, wird eine Warnung   ausgegeben, wenn diese Ganzzahl dem Zeiger zugeordnet ist; jedoch mit   die Besetzung, wird diese Warnung nicht erzeugt wird, einen Fehler zu verstecken. Auf bestimmte   Architekturen und Datenmodelle (wie LP64 auf 64-Bit-Systemen, bei denen   lang und Zeiger sind 64-Bit- und int ist 32-bit), kann dieser Fehler   tatsächlich zu undefinierten Verhalten, wie die implizit deklariert   malloc gibt einen 32-Bit-Wert, während der tatsächlich definierten Funktion   gibt einen 64-Bit-Wert. Je nach Aufrufkonventionen und Speichern   Layout, kann dies in Stapel Zerschlagung führen. Dieses Problem ist weniger wahrscheinlich,   unbemerkt in modernen Compilern zu gehen, da sie gleichmäßig produzieren   Warnungen, dass eine nicht angemeldete Funktion verwendet worden ist, so wird eine Warnung   noch erscheinen. Zum Beispiel Standardverhalten des GCC ist ein zeigen,   Warnung, dass „unvereinbar implizite Deklaration der eingebauten einliest   Funktion“, unabhängig davon, ob die Besetzung vorhanden ist oder nicht.

  •   
  • Wenn der Typ des Zeigers auf seine Erklärung geändert wird, kann man   Außerdem müssen alle Linien ändern, in dem malloc genannt wird und gegossen.

  •   

Obwohl malloc ohne das Gießen bevorzugtes Verfahren und die meisten erfahrenen Programmierer es wählen , sollten Sie je nachdem Sie wie die Probleme bewusst ist.

das heißt: Wenn Sie brauchen, um C-Programm als C ++ (Obwohl das ist eigenständige Sprache) sollten Sie verwenden malloc mit dem Gießen zu kompilieren.

In C können Sie implizit eine Lücke Zeiger auf jede andere Art von Zeiger umwandeln, so ein gegossenes nicht notwendig ist. eine Verwendung von für den flüchtigen Beobachter könnte darauf hindeuten, dass es einen Grund, warum man benötigt, was irreführend sein kann.

Sie werfen nicht das Ergebnis von malloc, da dies sinnlos Unordnung zu Ihrem Code erstellt.

Der häufigste Grund, warum Menschen das Ergebnis von malloc werfen, weil sie darüber, wie die C-Sprache funktioniert nicht sicher sind. Das ist ein Warnzeichen: Wenn Sie nicht wissen, wie eine bestimmte Sprache Mechanismus funktioniert, dann nicht nehmen eine Vermutung. Schauen Sie es oben oder fragen auf Stack-Überlauf.

Einige Kommentare:

  • A void-Zeiger kann, ohne eine explizite Umwandlung (C11 6.3.2.3 und 6.5.16.1).

  • nach / von jedem anderen Zeigertyp umgewandelt werden,
  • C ++ wird jedoch keine implizite Umwandlung zwischen void* und anderen Zeigertyp ermöglichen. Also in C ++, hätte die Besetzung richtig gewesen. Aber wenn Sie in C ++ programmieren, sollten Sie new und nicht malloc () verwenden. Und Sie sollten nie C-Code unter Verwendung eines C ++ Compiler kompiliert werden.

    Wenn Sie sowohl die C- und C ++ mit dem gleichen Quellcode zu unterstützen, verwenden Sie Compiler-Switches, die Unterschiede zu markieren. Versuchen Sie nicht, die beiden Sprachstandards mit dem gleichen Code zu sättigen, weil sie nicht kompatibel sind.

  • Wenn ein C-Compiler keine Funktion finden können, weil Sie den Header enthalten vergessen haben, erhalten Sie einen Compiler / Linker-Fehler über das bekommen. Also, wenn Sie vergessen haben, <stdlib.h> das ist kein großes Problem zu schließen, werden Sie nicht in der Lage sein, Ihr Programm zu bauen.

  • Auf alten Compiler, der eine Version des Standards folgen, die mehr als 25 Jahre alt ist, schließen <stdlib.h> zu vergessen in gefährlichem Verhalten führen würde. Da in dieser alten Standard-Funktionen ohne sichtbaren Prototyp implizit konvertierten den Rückgabetyp int. ausdrücklich Casting das Ergebnis von malloc würde dann diesen Fehler verbergen weg.

    Aber das ist wirklich kein Thema. Sie sind nicht 25 Jahre alt Computer, also warum sollten Sie 25 Jahre alt Compiler verwenden?

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

Casting den Wert von malloc() zurückgegeben wird nun nicht nötig, aber ich möchte einen Punkt hinzufügen, dass niemand darauf hingewiesen hat, scheint:

In den alten Tagen, das heißt, bevor ANSI C die void * als gattungs von Zeigern liefert, ist char * der Typ für eine solche Nutzung. In diesem Fall kann die Besetzung der Compiler-Warnungen geschlossen.

Referenz: C FAQ

Es ist nicht zwingend notwendig, die Ergebnisse von malloc zu werfen, da es void* zurückkehrt, und ein void* kann auf jeden Datentyp hingewiesen werden.

Nur meine Erfahrung hinzufügen, Computertechnik studiert ich sehe, dass die zwei oder drei Professoren, die ich schreibe in C gesehen immer malloc werfen, aber die, die ich (mit einem riesigen CV und das Verständnis von C) gefragt hat mir gesagt, dass es absolut unnötig, sondern nur die Studenten in die Mentalität des Seins absolut spezifisch sein, absolut spezifisch, und gewöhnungsbedürftig. Im Wesentlichen nichts ändern Gießen wird nicht, wie es funktioniert, es tut genau das, was sie sagt, Speicher reserviert, und Gießen es hat keine Auswirkungen, erhalten Sie den gleichen Speicher, und selbst wenn man es auf etwas anderes aus Versehen geworfen (und irgendwie Compiler umgehen Fehler) C wird es die gleiche Art und Weise zuzugreifen.

Edit: Gießen hat einen gewissen Punkt. Wenn Sie Array-Notation verwenden, erzeugt der Code muss wissen, wie viele Speicherplätze es vorzurücken hat den Anfang des nächsten Elements zu erreichen, wird dies durch Gießen erreicht. Auf diese Weise wissen Sie, dass für ein Doppel Sie 8 Bytes voraus gehen, während für ein int Sie 4 gehen, und so weiter. So hat es keine Auswirkung, wenn Sie die Zeigernotation verwenden, in Array-Notation wird es notwendig ist.

Dies ist, was der GNU C Library Reference Handbuch sagt:

  

Sie können speichern Sie das Ergebnis von malloc in jede Zeigervariable ohne ein   gegossen, weil ISO C automatisch den Typ void * in eine andere umwandelt,   Art des Zeigers, wenn notwendig. Aber die Besetzung ist in Kontexte notwendig   andere als Zuweisungsoperatoren oder wenn Sie Ihren Code ausführen möchten vielleicht   in der traditionellen C.

Und in der Tat die ISO C11 Standard (P347) so sagt:

  

Der Zeiger zurückgegeben, wenn die Zuordnung gelingt es in geeigneter Weise so ausgerichtet ist,   dass sie kann mit einem auf einen Zeiger auf jede Art von Objekt zugeordnet werden,   grundlegende Ausrichtungsanforderung und dann ein solcher für den Zugriff   Objekt oder eine Reihe solcher Objekte in dem zugewiesenen Raum (bis der   Raum ist ausdrücklich freigegeben)

Ein void-Zeiger ist ein allgemeiner Zeiger und C unterstützt implizite Konvertierung von einem Hohlraumzeigertyp auf andere Arten, so gibt es keine Notwendigkeit, davon explizit typecasting.

Wenn Sie jedoch den gleichen Code arbeiten perfekt kompatibel auf einer C ++ Plattform wollen, die nicht implizite Konvertierung nicht unterstützt, müssen Sie die Schublade gesteckt tun, so dass es alle auf Verwendbarkeit abhängig ist.

Der zurück Typ void *, die auf die gewünschte Art des Datenzeigers, um zu gieße dereferenceable werden kann.

In der C-Sprache, ein void-Zeiger kann zu jedem Zeiger zugewiesen werden, weshalb Sie keine Typumwandlung verwendet werden sollen. Wenn Sie „type safe“ Zuweisung wollen, kann ich die folgenden Makro-Funktionen empfehlen, die ich immer in meinen C-Projekten verwenden:

#include <stdlib.h>
#define NEW_ARRAY(ptr, n) (ptr) = malloc((n) * sizeof *(ptr))
#define NEW(ptr) NEW_ARRAY((ptr), 1)

Mit diesen anstelle man einfach sagen kann,

NEW_ARRAY(sieve, length);

Für nicht-dynamische Arrays, die dritte must-have Funktion Makro

#define LEN(arr) (sizeof (arr) / sizeof (arr)[0])

das Array macht Schleifen sicherer und bequemer:

int i, a[100];

for (i = 0; i < LEN(a); i++) {
   ...
}

Es hängt von der Programmiersprache und Compiler. Wenn Sie malloc in C dort verwenden, besteht keine Notwendigkeit, geben Sie ihn werfen, da sie automatisch Guss geben wird, aber wenn Ihr mit C ++, dann sollten Sie Guss geben, weil malloc eine void* Typ zurück.

Die Menschen auf GCC und Clang verwendet werden verdorben. Es ist nicht alles, was gut da draußen.

Ich habe im Laufe der Jahre ziemlich entsetzt gewesen von dem staggeringly im Alter von Compilern mir benötigt habe zu verwenden. Oft Unternehmen und Manager übernehmen einen ultra-konservativen Ansatz an sich verändernde Compiler und wird nicht einmal Test , wenn ein neuer Compiler (mit einer besseren Einhaltung von Standards und Code-Optimierung) wird in ihrem System arbeiten. Die praktische Realität Entwickler für die Arbeit ist, dass, wenn Sie Codierung Sie Ihre Basen abdecken müssen und leider eine gute Gewohnheit mallocs Gießen ist, wenn man nicht kontrollieren kann, was Compiler Code angewendet werden kann.

Ich würde auch vorschlagen, dass viele Organisationen eine Codierungsstandard ihrer eigenen gelten und dass , die sollte die Methode Menschen sein folgen, wenn sie definiert ist. In Ermangelung eines ausdrücklichen Hinweises neige ich dazu, für die meisten wahrscheinlich zu gehen überall, anstatt sklavisch Einhaltung einer Norm zu kompilieren.

Das Argument, dass es unter dem aktuellen Standards nicht notwendig ist, ist durchaus gültig. Aber das Argument läßt die Praktikabilität der realen Welt. Wir codieren nicht in einer Welt, die von der Norm des Tages ausschließlich regiert, sondern durch die Praktikabilität von dem, was Ich mag „das lokale Management Realität Feld“ nennen. Und das ist gebogen und verdreht mehr als Raum-Zeit überhaupt war. : -)

YMMV.

Ich neige dazu, von Gießen malloc als defensiver Betrieb zu denken. Nicht schön, nicht perfekt, aber im Allgemeinen sicher. (Ehrlich gesagt, wenn Sie noch nicht stdlib.h dann enthalten Sie haben Weg mehr Probleme als malloc Gießen!).

ich in der Besetzung einfach gesagt Ablehnung des hässlichen Loches in dem Typsystem zu zeigen, die Codes wie der folgenden Ausschnitt ermöglicht, ohne Diagnose zu erstellen, auch wenn keine Zylinder verwendet werden, über die schlechte Umsetzung zu bringen:

double d;
void *p = &d;
int *q = p;

Ich wünsche, dass nicht existiert (und es nicht in C ++) und so warf ich. Es stellt meinen Geschmack und meine Programmier Politik. Ich bin Gießen nicht nur einen Zeiger, aber effektiv, einen Stimmzettel Casting und Dämonen austreiben von Dummheit . Wenn ich kann nicht wirklich Dummheit austreiben, dann zumindest lassen Sie mich das auszudrücken will so mit einer Geste des Protests zu tun.

In der Tat, eine gute Praxis ist malloc zu wickeln (und Freunde) mit Funktionen, die unsigned char * zurückkehren, und im Grunde nie void * in Ihrem Code zu verwenden. Wenn Sie ein generisches Zeiger-to-Any-Objekt benötigen, verwenden Sie ein char * oder unsigned char * und haben Abgüsse in beiden Richtungen. Die eine Entspannung, die verwöhnt werden kann, ist vielleicht Funktionen wie memset und memcpy ohne Casts mit.

Zum Thema Gießen und C ++ Kompatibilität, wenn Sie Ihren Code schreiben, so dass es kompiliert sowohl als C und C ++ (in dem Fall, dass Sie müssen warf den Rückgabewert von malloc bei der Zuordnung es zu etwas anderes als void *), können Sie für sich selbst eine sehr hilfreiche Sache tun: Sie Makros zum Gießen verwendet werden können, die zu C übersetzen ++ Casts, wenn sie als C ++ kompiliert, sondern auf eine C Guss reduzieren, wenn sie als C Kompilieren:

/* In a header somewhere */
#ifdef __cplusplus
#define strip_qual(TYPE, EXPR) (const_cast<TYPE>(EXPR))
#define convert(TYPE, EXPR) (static_cast<TYPE>(EXPR))
#define coerce(TYPE, EXPR) (reinterpret_cast<TYPE>(EXPR))
#else
#define strip_qual(TYPE, EXPR) ((TYPE) (EXPR))
#define convert(TYPE, EXPR) ((TYPE) (EXPR))
#define coerce(TYPE, EXPR) ((TYPE) (EXPR))
#endif

Wenn Sie diese Makros halten, dann eine einfache grep Suche Ihrer Code-Basis für diese Kennungen zeigt Ihnen, wo Sie alle Ihre Abgüsse sind, so können Sie überprüfen, ob einer von ihnen falsch sind.

Dann geht nach vorn, wenn Sie regelmäßig den Code mit C ++ kompilieren, wird die Verwendung eines geeigneten Guss erzwingen. Zum Beispiel, wenn Sie strip_qual verwenden nur einen const oder volatile, aber die Programmänderungen in einer solchen Art und Weise zu entfernen, die eine Typumwandlung jetzt beteiligt ist, erhalten Sie eine Diagnose bekommen, und Sie werden eine Kombination von Abgüssen verwenden, um das zu bekommen gewünschte Umwandlung.

Damit Sie auf diese Makros haften, die das GNU C ++ (nicht C!) Compiler hat eine schöne Eigenschaft:. Eine optionale Diagnose, die für alle Vorkommen von C-Stil produziert wird wirft

     -Wold-style-cast (C++ and Objective-C++ only)
         Warn if an old-style (C-style) cast to a non-void type is used
         within a C++ program.  The new-style casts (dynamic_cast,
         static_cast, reinterpret_cast, and const_cast) are less vulnerable
         to unintended effects and much easier to search for.

Wenn Sie Ihr C-Code kompiliert wie C ++, können Sie diese -Wold-style-cast Option verwenden, um alle Vorkommen der (type) Casting Syntax herauszufinden, die in den Code kriechen können, und folgen Sie dieser Diagnose, indem sie mit einer geeigneten Wahl aus den Reihen des ersetzende über Makros (oder eine Kombination, falls erforderlich).

Diese Behandlung von Umwandlungen ist die größte eigenständige technische Begründung für in einem „Clean C“ arbeiten. Die kombinierte C und C ++ Dialekt, der technisch wiederum rechtfertigt den Rückgabewert von malloc Gießen

Das Beste, was zu tun ist, wenn in C programmieren, wann immer es möglich ist:

  1. Erstellen Sie Ihr Programm einen C-Compiler mit allen Warnungen auf -Wall gedreht kompilieren durch und beheben alle Fehler und Warnungen
  2. Stellen Sie sicher, dass es keine Variablen als auto
  3. deklariert sind
  4. Dann kompilieren sie einen C ++ Compiler mit -Wall und -std=c++11 verwenden. Fix alle Fehler und Warnungen.
  5. kompilieren nun wieder den C-Compiler. Ihr Programm sollte nun kompilieren ohne Vorwarnung und enthält wenige Fehler.

Mit diesem Verfahren können Sie die Vorteile von C ++ strenge Typprüfung nehmen, so dass die Anzahl der Fehler zu reduzieren. Insbesondere Sie dieses Verfahren Kräfte umfassen stdlib.hor Sie bekommen

  

malloc wurde nicht in diesem Rahmen erklärt

und zwingt Sie auch das Ergebnis der malloc zu werfen oder Sie bekommen

  

ungültige Umwandlung von void* T*

oder was auch immer Ihr Ziel-Typ ist.

Die einzigen Vorteile von in C schreiben anstelle von C ++ kann ich finden sind

  1. C hat ein gut angegeben ABI
  2. C ++ kann mehr Code generieren [Ausnahmen, RTTI, Vorlagen, Laufzeit Polymorphismus]

Beachten Sie, dass der zweite Nachteil im Idealfall sollte verschwinden, wenn die Teilmenge gemeinsam C zusammen mit der Verwendung von statisch polymorpher Funktion.

Für diejenigen, die C ++ strenge Regeln unbequem finden, können wir die C ++ 11-Funktion mit abgeleiteten Typ verwenden

auto memblock=static_cast<T*>(malloc(n*sizeof(T))); //Mult may overflow...

Nein, Sie werfen nicht das Ergebnis von malloc().

Im Allgemeinen Sie wirft nicht zu oder von void * .

Ein typischer Grund gegeben, dies nicht zu tun ist, dass die Nicht #include <stdlib.h> unbemerkt bleiben konnte. Dies ist kein Problem mehr für eine lange Zeit jetzt als C99 gemacht implizite Funktionsdeklarationen illegal, also, wenn Ihr Compiler mindestens C99 entspricht, erhalten Sie eine Diagnosemeldung.

Aber es gibt einen viel stärker Grund nicht unnötig Zeiger einzuführen wirft:

In C, eine Zeiger Besetzung ist fast immer ein Fehler . Dies ist wegen der folgenden Regel ( §6.5 p7 in N1570, der letzte Entwurf für C11):

  

Ein Objekt hat seinen gespeicherten Wert nur durch einen Ausdruck L-Wertes zugegriffen hat, die eine von   folgende Typen:
  - eine Art kompatibel mit der effektiven Art des Objekts,
  - eine qualifizierte Version eines Typ kompatibel mit der effektiven Art des Objekts,
  - ein Typ, der mit oder ohne Vorzeichen-Typ ist mit dem effektiven Typ der entsprechenden   Objekt,
  - ein Typ, der mit oder ohne Vorzeichen Typ ist mit einer qualifizierten Version der entsprechenden   effektive Art des Objekts,
  - ein Aggregat oder Union Typ, der unter seinem einen der vorgenannten Arten umfasst   Mitglieder (darunter ein Mitglied einer Unteraggregat oder enthalten Vereinigung rekursiv), oder in   - a. Zeichentyp

Dies wird auch als strenge Aliasing-Regel bekannt . So ist der folgende Code ist nicht definiertes Verhalten :

long x = 5;
double *p = (double *)&x;
double y = *p;

Und manchmal überraschend, dass das Folgende auch:

struct foo { int x; };
struct bar { int x; int y; };
struct bar b = { 1, 2};
struct foo *p = (struct foo *)&b;
int z = p->x;

Manchmal Sie müssen Zeiger werfen, aber angesichts der strenge Aliasing Regel , haben Sie damit sehr vorsichtig sein. So kann jedes Auftreten eines Zeigers Guss in Ihrem Code ist ein Ort, den Sie auf haben nochmals überprüfen für ihre Gültigkeit . Daher Sie nie einen unnötigen Zeiger Guss schreiben.

tl; dr

Auf den Punkt gebracht: Weil in C, jede Auftreten eines Zeiger Guss sollte eine rote Fahne für Code erfordern besondere Aufmerksamkeit erhöhen, sollten Sie nie schreiben nicht notwendig Zeiger wirft.


Side Hinweise:

  • Es gibt Fälle, in denen Sie eigentlich Notwendigkeit ein gegossenes void *, z.B. wenn Sie einen Zeiger drucken:

    int x = 5;
    printf("%p\n", (void *)&x);
    

    Die Besetzung ist hier notwendig, da printf() eine variadische Funktion ist, so implizite Konvertierungen nicht funktionieren.

  • In C ++ ist die Situation anders. Casting-Typ Zeiger ist etwas häufig (und richtig), wenn mit Objekten von abgeleiteten Klassen zu tun. Daher macht es Sinn, dass in C ++, die Umwandlung in und aus void * nicht implizit. C ++ hat eine ganze Reihe von verschiedenen Aromen des Gießens.

Ich ziehe die Besetzung zu tun, aber nicht von Hand. Mein Favorit ist mit g_new und g_new0 Makros aus glib. Wenn glib nicht verwendet wird, würde ich Ähnliche Makros hinzufügen. Diese Makros reduzieren Code-Duplizierung ohne Typsicherheit zu beeinträchtigen. Wenn Sie der Typ falsch, würden Sie eine implizite Umwandlung zwischen Nicht-void-Zeiger erhalten, die eine Warnung (Fehler in C ++) verursachen würde. Wenn Sie vergessen, den Header enthalten, die g_new und g_new0 definiert, würden Sie einen Fehler. g_new und g_new0 beide nehmen die gleichen Argumente, im Gegensatz zu malloc, die weniger Argumente als calloc nimmt. Fügen Sie einfach 0 Null initialisierten Speicher zu erhalten. Der Code kann mit einem C ++ Compiler ohne Änderungen kompiliert werden.

Gießen ist nur für C ++ nicht C.In Fall, dass Sie werden mit einem C ++ Compiler Sie besser Compiler C ändern.

Das Konzept hinter void-Zeiger ist, dass es auf jeden Datentyp gegossen werden kann, warum malloc kehrt nichtig. Auch müssen Sie sich bewusst automatische Schublade gesteckt werden. So ist es nicht zwingend um den Zeiger zu werfen, obwohl Sie sie tun müssen. Es hilft bei dem Code sauber zu halten und hilft Debuggen

  1. Wie andere erwähnt, ist es nicht für C benötigt, sondern auch für C ++.

  2. Einschließlich der Besetzung einem C-Programm oder eine Funktion zu kompilieren, wie C ++.

  3. kann zulassen
  4. In C es nicht notwendig ist, da void * automatisch und sicher an jeden anderen Zeigertyp gefördert.

  5. Aber wenn man dann werfen, kann es einen Fehler verbergen, wenn Sie vergessen haben, zu schließen stdlib.h . Dies kann dazu führen, Abstürze (oder, schlimmer noch, nicht zu einem Absturz führen bis weit später in einem völlig anderen Teil des Codes).

    Da stdlib.h enthält der Prototyp für malloc gefunden wird. In dem Fehlen eines Prototyps für malloc verlangt der Standard, dass die C Compiler annimmt malloc gibt ein Int. Wenn es keine Besetzung, eine Warnung ausgegeben wird, wenn diese Ganzzahl dem Zeiger zugeordnet ist; jedoch mit den Darstellern, wird diese Warnung nicht erzeugt wird, einen Fehler zu verbergen.

Ein void-Zeiger ist ein allgemeiner Zeiger und C unterstützt implizite Konvertierung von einem Hohlraumzeigertyp auf andere Arten, so gibt es keine Notwendigkeit, davon explizit typecasting.

Wenn Sie jedoch den gleichen Code arbeiten perfekt kompatibel auf einer C ++ Plattform wollen, die nicht implizite Konvertierung nicht unterstützt, müssen Sie die Schublade gesteckt tun, so dass es alle auf Verwendbarkeit abhängig ist.

Das Gießen von malloc ist nicht notwendig, in C, aber zwingend in C ++.

Casting ist nicht notwendig, in C wegen:

  • void * automatisch und sicher an jeden anderen Zeigertyp im Fall von C gefördert werden.
  • Es kann ein Fehler verbergen, wenn Sie vergessen haben, <stdlib.h> aufzunehmen. Dies kann zu Abstürzen führen.
  • Wenn Zeiger und Zahlen sind unterschiedlich groß, dann eine Warnung versteckt sind durch Gießen und könnte Bits Ihrer zurück Adresse verlieren.
  • Wenn der Typ des Zeigers auf seine Erklärung geändert wird, kann man muss auch alle Zeilen ändern, wo malloc genannt wird und gegossen.

Auf der anderen Seite, Gießen kann die Portabilität des Programms erhöhen. das heißt, es kann ein C-Programm oder eine Funktion als C ++ kompilieren.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top