it-swarm.com.de

Werfe ich das Ergebnis von Malloc?

In diese Frage schlug jemand in einem Kommentar vor, dass ich nicht Wirke das Ergebnis von malloc, dh.

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

eher, als:

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

Warum sollte das so sein?

2285

Nein; Sie haben das Ergebnis nicht gewirkt, da:

  • Dies ist nicht erforderlich, da void * in diesem Fall automatisch und sicher zu einem anderen Zeigertyp hochgestuft wird.
  • Es fügt dem Code Unordnung hinzu, Casts 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, <stdlib.h> einzuschließen. Dies kann zu Abstürzen führen (oder, schlimmer noch, und nicht zu einem 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 Wirken und verlierst möglicherweise Teile deiner zurückgegebenen Adresse. Hinweis: Ab C11 sind implizite Funktionen nicht mehr in C enthalten, und dieser Punkt ist nicht mehr relevant, da nicht automatisch angenommen wird, dass nicht deklarierte Funktionen int zurückgeben.

Beachten Sie zur Verdeutlichung, dass ich sagte: "Du gibst nicht", nicht "Du brauchst nicht zu gießen". Meiner Meinung nach ist es ein Fehler, die Besetzung einzubeziehen, auch wenn Sie es richtig verstanden haben. Das hat einfach keine Vorteile, aber eine Reihe von potenziellen Risiken, einschließlich der Besetzung, weisen darauf hin, dass Sie die Risiken nicht kennen.

Beachten Sie auch, wie Kommentatoren betonen, dass das oben Gesagte von C und nicht von C++ handelt. Ich glaube fest an C und C++ als getrennte Sprachen.

Zum Hinzufügen wiederholt Ihr Code unnötigerweise die Typinformationen (int), die Fehler verursachen können. Es ist besser, den zum Speichern des Rückgabewerts verwendeten Zeiger zu dereferenzieren, um die beiden zu "sperren":

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

Dadurch wird auch length zur besseren Sichtbarkeit nach vorne verschoben und die redundanten Klammern mit sizeof entfernt. 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! :)


Wenn Sie length nach vorne bewegen , kann in einigen seltenen Fällen die Sichtbarkeit erhöhen. Beachten Sie jedoch auch, dass dies im Allgemeinen der Fall sein sollte schreibe den Ausdruck besser als:

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

Da das sizeof zuerst beibehalten wird, wird in diesem Fall sichergestellt, dass die Multiplikation mit mindestens size_t math erfolgt.

Vergleichen Sie: malloc(sizeof *sieve * length * width) vs. malloc(length * width * sizeof *sieve) Die zweite kann den length * width überlaufen lassen, wenn width und length kleinere Typen als size_t sind.

2105
unwind

In C muss der Rückgabewert von malloc nicht umgewandelt werden. Der von malloc zurückgegebene Zeiger auf ungültig 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 besteht darin, Folgendes zu verwenden:

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

dies befreit Sie zusätzlich von der Sorge, die rechte Seite des Ausdrucks zu ändern, wenn Sie den Typ von sieve ändern.

Casts sind schlecht, wie die Leute darauf hingewiesen haben. Speziell Zeigerabdrücke.

354
dirkgently

Wie bereits erwähnt, wird es nicht für C, sondern für C++ benötigt. Wenn Sie glauben, dass Sie Ihren C-Code mit einem C++ - Compiler kompilieren werden, können Sie aus welchen Gründen auch immer, stattdessen 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

Auf diese Weise können Sie es immer noch sehr kompakt schreiben:

int *sieve = NEW(int, 1);

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

162
quinmars

Aus der Wikipedia :

Vorteile zum Gießen

  • Durch das Einbeziehen der Besetzung kann ein C-Programm oder eine C++ - Funktion kompiliert werden.

  • Die Besetzung erlaubt malloc-Versionen vor 1989, die ursprünglich char * zurückgaben.

  • Casting kann dem Entwickler dabei helfen, Inkonsistenzen bei der Schriftgrößenänderung zu erkennen, falls sich der Typ des Zielzeigers ändert, insbesondere wenn der Zeiger weit vom Aufruf von malloc () entfernt deklariert ist (obwohl moderne Compiler und statische Analysatoren bei einem solchen Verhalten warnen können, ohne dass das Casting erforderlich ist).

Nachteile beim Casting

  • Nach dem ANSI C-Standard ist die Umwandlung überflüssig.

  • Das Hinzufügen der Besetzung kann das Versagen maskieren, den Header stdlib.h einzuschließen, in dem sich der Prototyp für malloc befindet. In Ermangelung eines Prototyps für malloc verlangt der Standard, dass der C-Compiler annimmt, 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, da ein Fehler verborgen bleibt. Auf bestimmten Architekturen und Datenmodellen (wie LP64 auf 64-Bit-Systemen, bei denen long und pointers 64-Bit und int 32-Bit sind) kann dieser Fehler tatsächlich zu undefiniertem Verhalten führen, da das implizit deklarierte malloc einen 32-Bit-Wert zurückgibt. Bitwert, während die tatsächlich definierte Funktion einen 64-Bit-Wert zurückgibt. Abhängig von Aufrufkonventionen und Speicherlayout kann dies zu Stack-Smashing führen. Es ist weniger wahrscheinlich, dass dieses Problem bei modernen Compilern unbemerkt bleibt, da sie einheitlich Warnungen erzeugen, dass eine nicht deklarierte Funktion verwendet wurde, sodass weiterhin eine Warnung angezeigt wird. In der Standardeinstellung von GCC wird beispielsweise eine Warnung angezeigt, die "inkompatible implizite Deklaration der integrierten Funktion" lautet, unabhängig davon, ob die Besetzung vorhanden ist oder nicht.

  • Wenn der Typ des Zeigers bei seiner Deklaration geändert wird, müssen möglicherweise auch alle Zeilen geändert werden, in denen malloc aufgerufen und umgewandelt wird.

Obwohl malloc ohne Casting die bevorzugte Methode ist und die meisten erfahrenen Programmierer es wählen , sollten Sie verwenden, wann immer Sie sich der Probleme bewusst sind.

d. h .: Wenn Sie ein C-Programm als C++ kompilieren müssen (obwohl dies eine separate Sprache ist), sollten Sie malloc beim Casting verwenden.

125
ashiquzzaman33

In C können Sie einen leeren Zeiger implizit in einen anderen Zeigertyp konvertieren, sodass keine Umwandlung erforderlich ist. Die Verwendung von one kann dem gelegentlichen Beobachter nahe legen, dass es einen Grund gibt, warum man benötigt wird, was irreführend sein kann.

100
PaulJWilliams

Das Ergebnis von malloc wird nicht gewirkt, da dies Ihrem Code sinnlose Unordnung verleiht.

Der häufigste Grund, warum Leute das Ergebnis von malloc werfen, ist, dass sie sich nicht sicher sind, wie die C-Sprache funktioniert. Das ist ein Warnsignal: Wenn Sie nicht wissen, wie ein bestimmter Sprachmechanismus funktioniert, dann nicht raten Sie. Schlagen Sie nach oder fragen Sie bei Stack Overflow.

Einige Kommentare:

  • Ein ungültiger Zeiger kann ohne explizite Umwandlung in einen beliebigen 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 Sie new und nicht malloc () verwenden. 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 eine Funktion nicht finden kann, weil Sie vergessen haben, den Header einzuschließen, erhalten Sie einen Compiler-/Linker-Fehler. Wenn Sie also vergessen haben, <stdlib.h> einzuschließen, das ist kein Problem, können Sie Ihr Programm nicht erstellen.

  • Auf alten Compilern, die einer Version des Standards folgen, die älter als 25 Jahre ist, würde das Vergessen von <stdlib.h> zu gefährlichem Verhalten führen. Denn in diesem alten Standard haben Funktionen ohne sichtbaren Prototyp den Rückgabetyp implizit in int konvertiert. Wenn Sie das Ergebnis explizit aus malloc übertragen, wird dieser Fehler ausgeblendet.

    Aber das ist wirklich kein Problem. Sie verwenden keinen 25 Jahre alten Computer. Warum sollten Sie einen 25 Jahre alten Compiler verwenden?

92
Lundin

In C erhalten Sie eine implizite Konvertierung von void* in einen anderen (Daten-) Zeiger.

86
EFraim

Das Casting des von malloc() zurückgegebenen Werts ist jetzt nicht erforderlich, aber ich möchte einen Punkt hinzufügen, auf den anscheinend niemand hingewiesen hat:

In alten Zeiten, d. H. Bevor ANSI C den void * als generischen Zeigertyp bereitstellt, ist char * der Typ für eine solche Verwendung. In diesem Fall kann die Besetzung die Compiler-Warnungen beenden.

Hinweis: C FAQ

67
Yu Hao

Die Ergebnisse von malloc müssen nicht zwingend umgewandelt werden, da void* zurückgegeben wird und ein void* auf einen beliebigen Datentyp verweisen kann.

50
user968000

Wenn ich meine Erfahrung als Informatiker hinzuzähle, stelle ich fest, dass die zwei oder drei Professoren, die ich in C gesehen 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, ordnet Speicher zu und das Casting bewirkt es nicht, Sie erhalten denselben Speicher, und selbst wenn Sie es versehentlich in etwas anderes umwandeln (und dem Compiler irgendwie ausweichen) Fehler) C wird auf die gleiche Weise darauf zugreifen.

Edit: 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 gehen, während Sie für ein Int 4 und so weiter gehen. Daher hat es keine Auswirkung, wenn Sie die Zeigernotation verwenden. In der Array-Notation ist dies erforderlich.

49
user3079666

Dies ist, was Die GNU C-Bibliotheksreferenz Handbuch sagt:

Sie können das Ergebnis von malloc in einer beliebigen Zeigervariable ohne Umwandlung speichern, da ISO C den Typ void * bei Bedarf automatisch in einen anderen Zeigertyp konvertiert. Die Umwandlung ist jedoch in anderen Kontexten als Zuweisungsoperatoren erforderlich oder wenn Sie möchten, dass Ihr Code in traditionellem C ausgeführt wird.

Und tatsächlich sagt das ISO C11 Standard (p347) so:

Der bei erfolgreicher Zuweisung zurückgegebene Zeiger ist in geeigneter Weise ausgerichtet, so dass er einem Zeiger auf einen beliebigen Objekttyp mit einer grundlegenden Ausrichtungsanforderung zugewiesen und dann verwendet werden kann, um auf ein solches Objekt oder ein Array solcher Objekte in dem zugewiesenen Bereich zuzugreifen (bis zum Speicherplatz wird explizit freigegeben)

31
Slothworks

Ein Void-Zeiger ist ein generischer Zeiger, und C unterstützt die implizite Konvertierung von einem Void-Zeigertyp in einen anderen Typ, 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.

30
Endeavour

Der zurückgegebene Typ ist void *, der in den gewünschten Datenzeigertyp umgewandelt werden kann, um dereferenzierbar zu sein.

29
swaps

In der Sprache C kann jedem Zeiger ein ungültiger Zeiger zugewiesen werden. Aus diesem Grund sollten Sie keine Typumwandlung verwenden. Wenn Sie eine "typsichere" Zuordnung wünschen, kann ich die folgenden Makrofunktionen empfehlen, die ich in meinen C-Projekten immer verwende:

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

Mit diesen können Sie einfach sagen

NEW_ARRAY(sieve, length);

Für nicht dynamische Arrays ist das dritte Muss-Funktionsmakro

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

das macht Array-Schleifen sicherer und bequemer:

int i, a[100];

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

Das hängt von der Programmiersprache und dem Compiler ab. Wenn Sie malloc in C verwenden, müssen Sie kein cast eingeben, da es automatisch cast eingibt. Wenn Sie jedoch C++ verwenden, sollten Sie cast eingeben, da malloc einen void* zurückgibt. Art.

26
Jeyamaran

Die Leute, die an GCC und Clang gewöhnt sind, sind verwöhnt. Es ist nicht so gut da draußen.

Ich war über die Jahre ziemlich entsetzt über die erstaunlich gealterten Compiler, die ich verwenden musste. Oft verfolgen Unternehmen und Manager einen äußerst konservativen Ansatz bei der Änderung von Compilern und werden nicht einmal testen , ob ein neuer Compiler (mit besserer Einhaltung von Standards und Codeoptimierung) dies tut arbeiten in ihrem System. Die praktische Realität für Entwickler ist, dass Sie beim Codieren Ihre Grundlagen abdecken müssen. Leider ist das Casting von mallocs eine gute Angewohnheit, wenn Sie nicht kontrollieren können, welcher Compiler auf Ihren Code angewendet wird.

Ich würde auch vorschlagen, dass viele Organisationen einen eigenen Kodierungsstandard anwenden und dass das die Methode sein sollte, der die Leute folgen, wenn es definiert ist. In Ermangelung einer expliziten Anleitung tendiere ich eher dazu, überall zu kompilieren, als mich an einen Standard zu halten.

Das Argument, dass es unter den gegenwärtigen Standards nicht notwendig ist, ist durchaus berechtigt. Dieses Argument lässt jedoch die praktischen Aspekte der realen Welt außer Acht. Wir codieren nicht in einer Welt, die ausschließlich vom Standard des Tages bestimmt wird, sondern nach den praktischen Aspekten dessen, was ich gerne als "Realitätsfeld des lokalen Managements" bezeichne. Und das ist mehr verbogen und verdreht als es die Raumzeit jemals war. :-)

YMMV.

Ich neige dazu, Malloc als Verteidigungsoperation zu betrachten. Nicht hübsch, nicht perfekt, aber im Allgemeinen sicher. (Ehrlich gesagt, wenn Sie stdlib.h nicht eingeschlossen haben, dann haben Sie viel mehr Probleme als das Gießen von malloc!).

16
StephenG

Ich habe die Besetzung nur eingefügt, um die Ablehnung der hässlichen Lücke im Typensystem zu demonstrieren, die es ermöglicht, Code wie den folgenden Ausschnitt ohne Diagnose zu kompilieren, obwohl keine Besetzungen verwendet werden, um die schlechte Konvertierung zu bewirken:

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

Ich wünschte, das gäbe es nicht (und das gibt es auch nicht in C++) und so habe ich gegossen. Es repräsentiert meinen Geschmack und meine Programmpolitik. Ich werfe nicht nur einen Zeiger, sondern auch einen Stimmzettel und Dämonen der Dummheit austreiben . Wenn ich nicht tatsächlich Dummheit ausstoßen kann, dann lassen Sie mich wenigstens den Wunsch äußern, dies mit einer Geste von Protest.

In der Tat ist es eine gute Praxis, malloc (und Freunde) mit Funktionen zu verpacken, die unsigned char * zurückgeben, und void * grundsätzlich niemals in Ihrem Code zu verwenden. Wenn Sie einen generischen Zeiger auf ein beliebiges Objekt benötigen, verwenden Sie einen char * oder unsigned char * und lassen Sie in beide Richtungen wirken. Die einzige Entspannung, der man sich vielleicht hingeben kann, ist die Verwendung von Funktionen wie memset und memcpy ohne Casts.

Zum Thema Casting und C++ - Kompatibilität: Wenn Sie Ihren Code so schreiben, dass er sowohl in C als auch in C++ kompiliert wird (in diesem Fall müssen Sie das Casting ausführen Wenn Sie den Wert malloc einem anderen Wert als void *) zuweisen, können Sie Folgendes tun: Sie können Makros für das Casting verwenden, die beim Kompilieren als C++ in C++ - Darstellungen umgewandelt werden Reduzieren auf einen C-Cast beim Kompilieren als C:

/* 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 sich an diese Makros halten, zeigt Ihnen eine einfache grep Suche in Ihrer Codebasis nach diesen Bezeichnern, wo sich all Ihre Besetzungen befinden, sodass Sie überprüfen können, ob eine von ihnen falsch ist.

Wenn Sie den Code anschließend regelmäßig mit C++ kompilieren, wird die Verwendung einer entsprechenden Umwandlung erzwungen. Wenn Sie beispielsweise strip_qual verwenden, um const oder volatile zu entfernen, das Programm sich jedoch so ändert, dass jetzt eine Typkonvertierung erfolgt, erhalten Sie eine Diagnose und Sie müssen eine Kombination von Casts verwenden, um die gewünschte Konvertierung zu erhalten.

Um Ihnen das Einhalten dieser Makros zu erleichtern, hat der Compiler GNU C++ (nicht C!) Eine schöne Funktion: eine optionale Diagnose, die für alle Vorkommen von C-Darstellungen erstellt wird.

 -Wold-Style-Cast (nur C++ und Objective-C++) 
 Warnen, wenn ein alter (C-Style) Cast in einen nicht-leeren Typ verwendet wird 
 ein C++ - Programm. Die neuen Besetzungen (dynamic_cast, 
 Static_cast, reinterpret_cast und const_cast) sind weniger anfällig für unbeabsichtigte Effekte und viel einfacher zu suchen. 

Wenn Ihr C-Code als C++ kompiliert wird, können Sie mit dieser Option -Wold-style-cast alle Vorkommen der Castingsyntax (type) ermitteln, die sich möglicherweise in den Code eingeschlichen haben, und diese Diagnosen durch eine ersetzen geeignete Auswahl aus den obigen Makros (oder gegebenenfalls eine Kombination).

Diese Behandlung von Konvertierungen ist die größte eigenständige technische Rechtfertigung für die Arbeit in einem "Bereinigten C": der kombinierte C- und C++ - Dialekt, der seinerseits die Umwandlung des Rückgabewerts von malloc technisch rechtfertigt.

14
Kaz

Ich mache die Besetzung lieber, aber nicht manuell. Mein Favorit verwendet die Makros g_new und g_new0 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 eingeben, erhalten Sie eine implizite Umwandlung zwischen nicht leeren Zeigern, die eine Warnung auslösen (Fehler in C++). Wenn Sie vergessen, den Header einzuschließen, der g_new und g_new0 definiert, wird eine Fehlermeldung angezeigt. g_new und g_new0 verwenden beide dieselben Argumente, im Gegensatz zu malloc, das weniger Argumente als calloc verwendet. Fügen Sie einfach 0 hinzu, um null initialisierten Speicher zu erhalten. Der Code kann mit einem C++ - Compiler ohne Änderungen kompiliert werden.

13
proski

Nein, Sie haben das Ergebnis von malloc() nicht gewirkt.

Im Allgemeinen, Sie nicht zu oder von void *.

Ein typischer Grund dafür ist, dass das Versagen von #include <stdlib.h> unbemerkt bleiben könnte. Dies ist seit langem kein Problem mehr, da C99 implizite Funktionsdeklarationen ungültig gemacht hat. Wenn Ihr Compiler also mindestens C99 entspricht, erhalten Sie eine Diagnosemeldung.

Aber es gibt einen viel stärkeren Grund keine unnötigen Zeigermodelle einzuführen:

In C ist ein Zeigerumwandlung ist fast immer ein Fehler. Dies liegt an der folgenden Regel (§6.5 p7 in N1570, dem neuesten Entwurf für C11):

Auf den gespeicherten Wert eines Objekts darf nur mit einem Wertausdruck eines der folgenden Typen zugegriffen werden:
- ein Typ, der mit dem effektiven Typ des Objekts kompatibel ist,
- eine qualifizierte Version eines Typs, der mit dem effektiven Typ des Objekts kompatibel ist,
- ein Typ, der der vorzeichenbehaftete oder vorzeichenlose Typ ist, der dem effektiven Typ des Objekts entspricht,
- ein Typ, der der mit oder ohne Vorzeichen versehene Typ ist, der einer qualifizierten Version des effektiven Typs des Objekts entspricht,
- ein Aggregat- oder Vereinigungstyp, zu dessen Mitgliedern einer der vorgenannten Typen gehört (einschließlich rekursiv eines Mitglieds einer Untergemeinde oder einer geschlossenen Vereinigung), oder
- ein Zeichentyp.

Dies wird auch als strenge Aliasing-Regel bezeichnet. Der folgende Code lautet also ndefiniertes Verhalten:

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

Und manchmal überraschend ist auch Folgendes:

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 müssen Sie do Zeiger setzen, aber angesichts der strengen Aliasing-Regel müssen Sie sehr vorsichtig damit umgehen. Jedes Vorkommen eines in Ihrem Code gesetzten Zeigers ist eine Stelle, an der Sie die Gültigkeit muss noch einmal überprüft werden. Daher schreiben Sie niemals eine unnötige Zeigerverbindung.

tl; dr

Auf den Punkt gebracht: Da in C any das Auftreten eines Zeigermodells eine rote Markierung für Code auslösen sollte, der besondere Aufmerksamkeit erfordert, sollten Sie niemals nicht erforderlich schreiben = Zeigerabdrücke.


Randnotizen:

  • Es gibt Fälle, in denen Sie tatsächlich brauchen eine Besetzung zu void *, z. Wenn Sie einen Zeiger drucken möchten:

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

    Die Besetzung ist hier erforderlich, da printf() eine variable Funktion ist, sodass implizite Konvertierungen nicht funktionieren.

  • In C++ ist die Situation anders. Das Umsetzen von Zeigertypen ist etwas gebräuchlich (und korrekt) im Umgang mit Objekten abgeleiteter Klassen. Daher ist es sinnvoll, dass in C++ die Konvertierung von und nach void *nicht implizit ist. C++ hat eine ganze Reihe verschiedener Casting-Varianten.

13
user2371524

Das Beste, wenn Sie in C programmieren, wann immer es möglich ist:

  1. Lassen Sie Ihr Programm über einen C-Compiler kompilieren, wobei alle Warnungen auf -Wall gesetzt sind, und korrigieren Sie alle Fehler und Warnungen
  2. Stellen Sie sicher, dass keine Variablen als auto deklariert sind.
  3. Kompilieren Sie es anschließend mit einem C++ - Compiler mit -Wall und -std=c++11. Beheben Sie alle Fehler und Warnungen.
  4. Übersetzen Sie nun wieder mit dem C-Compiler. Ihr Programm sollte jetzt ohne Vorwarnung kompiliert werden und weniger Fehler enthalten.

Mit dieser Prozedur können Sie die strikte Typprüfung in C++ nutzen und so die Anzahl der Fehler reduzieren. Diese Prozedur zwingt Sie insbesondere dazu, stdlib.h einzuschließen, oder Sie erhalten

malloc wurde in diesem Bereich nicht deklariert

und zwingt dich auch, das Ergebnis von malloc zu wirken, sonst bekommst du

ungültige Konvertierung von void* nach T*

oder was auch immer Ihr Zieltyp ist.

Die einzigen Vorteile des Schreibens in C anstelle von C++, die ich finden kann, sind

  1. C hat einen gut spezifizierten ABI
  2. C++ generiert möglicherweise mehr Code [Ausnahmen, RTTI, Vorlagen, Laufzeit Polymorphismus]

Beachten Sie, dass die zweiten Nachteile im Idealfall verschwinden sollten, wenn Sie die Teilmenge von C zusammen mit dem polymorphen Merkmal statisch verwenden.

Für diejenigen, die strenge C++ - Regeln für unpraktisch halten, können wir die C++ 11-Funktion mit abgeleitetem Typ verwenden

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

Das 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.

11
user3949394

Das Konzept hinter void pointer ist, dass es 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 zu setzen, obwohl Sie dies tun müssen. Es hilft dabei, den Code sauber zu halten und hilft beim Debuggen

10
iec2011007

Ein Void-Zeiger ist ein generischer Zeiger, und C unterstützt die implizite Konvertierung von einem Void-Zeigertyp in einen anderen Typ, 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.

8
  1. Wie bereits erwähnt, wird es nicht für C, sondern für C++ benötigt.

  2. Durch das Einbeziehen der Besetzung kann ein C-Programm oder eine C++ - Funktion kompiliert werden.

  3. In C ist dies nicht erforderlich, da void * automatisch und sicher zu einem anderen Zeigertyp hochgestuft wird.

  4. Aber wenn Sie dann zaubern, kann es einen Fehler verbergen, wenn Sie vergessen haben, stdlib.h einzuschließen. Dies kann zu Abstürzen führen (oder schlimmer noch, einen Absturz erst viel später in einem völlig anderen Teil des Codes verursachen).

    Denn stdlib.h enthält den Prototyp für malloc. In Ermangelung eines Prototyps für malloc verlangt der Standard, dass der C-Compiler annimmt, 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, da ein Fehler verborgen bleibt.

8
Mohit

Das Casting von malloc ist in C nicht erforderlich, aber in C++ obligatorisch.

Casting ist in C unnötig, weil:

  • void * wird im Fall von C automatisch und sicher zu jedem anderen Zeigertyp heraufgestuft.
  • Es kann einen Fehler verbergen, wenn Sie vergessen haben, <stdlib.h> einzuschließen. Dies kann zu Abstürzen führen.
  • Wenn Zeiger und Ganzzahlen unterschiedlich groß sind, wird eine Warnung ausgeblendet, und möglicherweise gehen Teile der zurückgegebenen Adresse verloren.
  • Wenn der Typ des Zeigers bei seiner Deklaration geändert wird, müssen möglicherweise auch alle Zeilen geändert werden, in denen malloc aufgerufen und umgewandelt wird.

Andererseits kann das Casting die Portabilität Ihres Programms erhöhen. es ermöglicht einem C-Programm oder einer C++ - Funktion, kompiliert zu werden.

5
Aashish