Frage

Ich habe einen Kommentar auf meine Antwort auf diesen Thread:

Malloc innerhalb ein Funktionsaufruf erscheint auf Rückkehr befreit werden immer?

Kurz gesagt hatte ich Code wie folgt:

int * somefunc (void)
{
  int * temp = (int*) malloc (sizeof (int));
  temp[0] = 0;
  return temp;
}

Ich habe diesen Kommentar:

  

Kann ich nur sagen, bitte werfen Sie nicht die   Rückgabewert von malloc? Es ist nicht   erforderlich und kann Fehler verbergen.

Ich bin damit einverstanden, dass die Besetzung nicht in C erforderlich ist, ist es zwingend in C ++, so dass ich sie in der Regel nur hinzufügen, falls ich in den Hafen haben Sie den Code in C ++ einen Tag.

Allerdings frage ich mich, wie wirft wie diese Fehler verstecken. Irgendwelche Ideen?

Edit:

Es scheint, wie es gibt sehr gute und gültige Argumente auf beiden Seiten. Vielen Dank für die Buchung, Leute.

War es hilfreich?

Lösung

Es scheint angemessen, poste ich eine Antwort, da ich den Kommentar verfasst: P

Grundsätzlich, wenn Sie vergessen schließen stdlib.h der Compiler annehmen malloc eine int zurückgibt. Ohne Gießen, erhalten Sie eine Warnung erhalten. Mit Gießen werden Sie nicht.

So durch Gießen Sie nichts zu bekommen, und die Gefahr der Unterdrückung legitime Warnungen führen.

Viel darüber geschrieben wird, eine schnelle Google-Suche wird nach oben näheren Erläuterungen.

Bearbeiten

Es wurde argumentiert, dass

TYPE * p;
p = (TYPE *)malloc(n*sizeof(TYPE));

macht es offensichtlich, wenn Sie versehentlich nicht genug Speicher reservieren, da sagen wir, Sie dachten, p war TYPe nicht TYPE, und somit sollten wir malloc werfen, weil der Vorteil dieser Methode überschreibt die geringeren Kosten von Compiler-Warnungen versehentlich unterdrückt wird.

Ich möchte 2 Dinge hinweisen:

  1. Sie sollten p = malloc(sizeof(*p)*n); schreiben, um immer sicherzustellen, dass Sie die richtige Menge an Raum malloc
  2. mit dem obigen Ansatz, müssen Sie Änderungen an 3 Stellen machen, wenn Sie jemals die Art der p ändern: einmal in der Erklärung, einmal in den malloc, und einmal in der Besetzung.

Kurz gesagt, ich noch persönlich glaube, dass es nicht notwendig ist, den Rückgabewert von malloc zum Gießen und es ist sicherlich nicht die beste Praxis.

Andere Tipps

Diese Frage wird markiert sowohl für C und C ++, so dass es mindestens zwei Antworten hat, IMHO:

C

Ähem ... Mach doch, was Sie wollen.

Ich glaube, der Grund gegeben oben „Wenn Sie nicht enthalten‚stdlib‘dann werden Sie nicht eine Warnung“ keine gültige ein, weil man nicht auf diese Art von Hacks verlassen sollte nicht vergessen, einen Header enthalten .

Der wahre Grund, dass Sie machen konnte nicht schreibt die Besetzung ist, dass die C-Compiler bereits gegossen lautlos ein void * in dem, was Zeigertyp gewünscht wird, und so, es selbst zu tun ist übertrieben und nutzlos.

Wenn Sie Typsicherheit haben, können Sie entweder auf C ++ wechseln oder Ihre eigene Wrapper-Funktion schreiben, wie:

int * malloc_Int(size_t p_iSize) /* number of ints wanted */
{
   return malloc(sizeof(int) * p_iSize) ;
}

C ++

Manchmal, auch in C ++, müssen Sie profitieren von dem malloc / realloc / Frei utils machen. Dann werden Sie haben zu werfen. Aber Sie wussten bereits, dass. Mit static_cast <> () wird besser, wie immer, als C-Casts.

Und in C, könnten Sie malloc außer Kraft setzen (und realloc, etc.) durch Vorlagen Typsicherheit zu erreichen:

template <typename T>
T * myMalloc(const size_t p_iSize)
{
 return static_cast<T *>(malloc(sizeof(T) * p_iSize)) ;
}

Welche verwendet werden würde, wie:

int * p = myMalloc<int>(25) ;
free(p) ;

MyStruct * p2 = myMalloc<MyStruct>(12) ;
free(p2) ;

und der folgende Code ein:

// error: cannot convert ‘int*’ to ‘short int*’ in initialization
short * p = myMalloc<int>(25) ;
free(p) ;

wird nicht kompiliert, so, keine Problemo .

Alles in allem in reinen C ++, Sie haben jetzt keine Entschuldigung, wenn jemand findet mehr als ein C malloc in Ihrem Code ... : -)

C + C ++ Crossover

Manchmal Sie Code zu erzeugen, die sowohl in C kompilieren und in C ++ (für welchen Gründen auch immer ... Ist es nicht an der Stelle des C ++ extern "C" {} Block?). In diesem Fall verlangt C ++ die Besetzung, aber C wird das static_cast Schlüsselwort nicht verstehen, so dass die Lösung ist die C-Casts (die in C noch legal ist ++ für genau diese Art von Gründen).

Beachten Sie, dass auch mit reinem C-Code zu schreiben, ist es mit einem C ++ Compiler kompiliert werden Ihnen viel mehr Warnungen und Fehlermeldungen erhält (zum Beispiel versucht, eine Funktion zu verwenden, ohne es zuerst erklärt wird nicht kompiliert, im Gegensatz zu dem oben genannten Fehler) .

Also, auf der sicheren Seite zu sein, Code schreiben, sauber in C ++, Studie kompiliert und die Warnungen korrigieren, und verwenden Sie dann die C-Compiler die endgültigen binären zu erzeugen. Das bedeutet wiederum, schreibt die Besetzung, in einem C-Casts.

Eine mögliche Fehler es vorstellen kann, ist, wenn Sie auf einem 64-Bit-System kompilieren C (nicht C ++).

Grundsätzlich, wenn Sie vergessen stdlib.h enthalten, wird die Standard-int Regel gelten. So wird der Compiler glücklich, dass malloc nehmen hat den Prototyp int malloc(); auf vielen 64-Bit-Systemen ist ein int 32-Bit und ein Zeiger ist 64-Bit.

Uh oh, wird der Wert abgeschnitten und nur die unteren 32 Bits des Zeigers erhalten! Nun, wenn Sie den Rückgabewert von malloc werfen, wird dieser Fehler durch die Besetzung versteckt. Aber wenn Sie nicht eine Fehlermeldung angezeigt werden (etwas die Art von „nicht int T * convert“).

Dies gilt nicht für C ++ natürlich aus 2 Gründen. Erstens ist es keine Standard int Regel hat, zweitens bedarf es die Besetzung.

Alles in allem aber sollten Sie gerade neu in C ++ Code sowieso :-P.

Nun, ich denke, es ist das genaue Gegenteil - immer werfen sie direkt an den benötigten Typ. Lesen Sie hier!

Die „vergessen stdlib.h“ Argument ist ein Strohmann. Moderne Compiler erkennen und warnen vor dem Problem (gcc -Wall).

Sie sollten immer das Ergebnis von malloc sofort gegossen. Nicht so tun sollte als Fehler angesehen werden, und zwar nicht nur, weil es wie C ++ scheitern. Wenn Sie eine Maschinenarchitektur mit verschiedenen Arten von Zeigern, zum Beispiel Targeting, könnten Sie mit einem sehr heikel Fehler aufzuwickeln, wenn Sie nicht in der Besetzung setzen Sie.

Bearbeiten : Die commentor Evan Teran korrekt ist. Mein Fehler war, zu denken, dass der Compiler keine Arbeit auf einem void-Zeiger in jedem Kontext zu tun hat. Ich ausflippen, wenn ich von FAR-Pointer Fehler zu denken, so meine Intuition alles zu werfen ist. Dank Evan!

Eigentlich ist der einzige Weg, ein gegossenes einen Fehler verbergen könnte, ist, wenn Sie von einem Datentyp zu einem kleineren Datentyp und verlorene Daten konvertieren wurden, oder wenn Sie Birnen Äpfel wurden zu konvertieren. Nehmen Sie das folgende Beispiel:

int int_array[10];
/* initialize array */
int *p = &(int_array[3]);
short *sp = (short *)p;
short my_val = *sp;

in diesem Fall die Umstellung auf kurze würden einige Daten aus dem int fallen lassen. Und dann dieser Fall:

struct {
    /* something */
} my_struct[100];

int my_int_array[100];
/* initialize array */
struct my_struct *p = &(my_int_array[99]);

, in dem würden Sie auf die falsche Art von Daten zeigen am Ende, oder sogar auf ungültige Speicher.

Aber im Allgemeinen, und wenn Sie wissen, was Sie tun, ist es OK, um das Gießen zu tun. Umso mehr, wenn Sie bekommen Speicher von malloc, die einen void-Zeiger zurück geschieht, die Sie nicht verwenden können, wenn Sie es gegossen und die meisten Compiler warnt Sie, wenn Sie etwas, das Gießen der L-Wert (den Wert der linke Seite der Zuweisung) nicht sowieso nehmen.

#if CPLUSPLUS
#define MALLOC_CAST(T) (T)
#else
#define MALLOC_CAST(T)
#endif
...
int * p;
p = MALLOC_CAST(int *) malloc(sizeof(int) * n);

oder alternativ

#if CPLUSPLUS
#define MYMALLOC(T, N) static_cast<T*>(malloc(sizeof(T) * N))
#else
#define MYMALLOC(T, N) malloc(sizeof(T) * N)
#endif
...
int * p;
p = MYMALLOC(int, n);

Die Menschen haben bereits zitierten die Gründe, warum ich Trab in der Regel: das alte (nicht mehr für die meisten Compiler) Argument nicht stdlib.h einschließlich und sizeof *p mit um sicherzustellen, dass immer die Art und Größe entsprechen, unabhängig von späterer Aktualisierung. Ich möchte ein weiteres Argument gegen Gießen hinweisen. Es ist ein kleiner, aber ich denke, es gilt.

C ist ziemlich schwach typisiert. Die meisten sicheren Typkonvertierungen automatisch geschehen, und unsichersten diejenigen erfordern eine Besetzung. Bedenken Sie:

int from_f(float f)
{
    return *(int *)&f;
}

Das ist, gefährlicher Code. Es ist technisch nicht definiertes Verhalten, obwohl in der Praxis auf fast jeder Plattform, um die gleiche Sache zu tun, es wird Sie es laufen. Und die Besetzung hilft Ihnen sagen, "Dieser Code ein schrecklicher Hack ist."

Bedenken Sie:

int *p = (int *)malloc(sizeof(int) * 10);

Ich sehe eine Besetzung, und ich frage mich: „Warum ist das notwendig? Wo der Hack ist?“ Es stellt sich Haare auf meinem Hals, dass es etwas Böses los ist, wenn in der Tat der Code völlig harmlos ist.

Solange wir C verwenden, Abgüsse (insbesondere Zeiger Abgüsse) sind eine Art zu sagen, „Es ist etwas böse und leicht zerbrechliche hier los ist.“ Sie können erreichen, was Sie erreicht brauchen, aber sie zeigen Ihnen und zukünftige Maintainer, dass die Kinder sind nicht in Ordnung.

Abgüsse Verwendung auf jedem malloc vermindert den „Hack“ Anzeige des Zeigers Guss. Es macht es weniger schrill Dinge wie *(int *)&f; zu sehen.

Hinweis: C und C ++ sind in verschiedenen Sprachen. C ist schwach typisiert, C ++ mehr ist stark typisiert. Die Abgüsse sind notwendig in C ++, obwohl sie ergeben keine Hinweise auf einen Hack überhaupt, wegen (in meiner bescheidenen Meinung nach) das unnötig starke C ++ Typsystem. (Wirklich, dieser spezielle Fall ist der einzige Ort, wo ich denke, das C ++ Typ-System ist „zu stark“, aber ich kann nicht denken Sie an jedem Ort, wo es ist „zu schwach“, die es für meinen Geschmack insgesamt zu stark macht.)

Wenn Sie sind besorgt über C ++ Kompatibilität, nicht. Wenn Sie C schreiben, verwenden Sie einen C-Compiler. Es gibt viele wirklich gute für jede Plattform avaliable. Wenn aus irgendeinem albernen Grund Sie wurde C-Code zu schreiben, die sauber wie C ++ kompiliert, bist du nicht wirklich schreiben C. Wenn Sie an Port C zu C benötigen ++, sollten Sie viele Änderungen werden machen Ihren C-Code mehr idiomatischen C ++ zu machen.

Wenn Sie eines nicht tun können, Ihr Code wird nicht schön sein, egal was Sie tun, so dass es nicht wirklich wichtig, wie Sie sich entscheiden, an diesem Punkt zu werfen. Ich mag die Idee Vorlagen mit einem neuen allocator zu machen, die die richtige Art gibt, aber das ist im Grunde nur die new Stichwort neu zu erfinden.

eine Funktion Casting, die (void *) gibt stattdessen ein (int *) zu sein, ist harmlos. Sie eine Art von Zeiger auf einen anderen sind Gießen

Casting eine Funktion, die einen Integer zurückgibt, anstatt zu sein, ein Zeiger höchstwahrscheinlich falsch. Der Compiler würde es hat man es nicht explizit gekennzeichnet hat geworfen.

Ein möglicher Fehler könnte (auf je ist, ob was Sie wirklich wollen oder nicht) mit einer Größenskala mallocing wird und auf einen Zeiger eines anderen Typs zuweisen. Z.B.

int *temp = (int *)malloc(sizeof(double));

Es kann Fälle geben, in denen Sie dies tun wollen, aber ich vermute, dass sie selten sind.

Ich denke, Sie sollten die eingegossenen setzen Bedenken Sie, dass es drei Standorte für Typen:.

T1 *p;
p = (T2*) malloc(sizeof(T3));

Die beiden Zeilen Code könnte weit voneinander getrennt werden. Deshalb ist es gut, dass der Compiler erzwingen dass T1 == T2. Es ist einfacher, visuell, dass T2 überprüfen == T3.

Wenn Sie den T2 Guss verpassen, dann muss man hoffen, dass T1 == T3.

Auf der anderen Seite haben Sie das fehlende stdlib.h Argument -. Aber ich denke, es ist weniger wahrscheinlich, dass ein Problem sein

Auf der anderen Seite, wenn Sie jemals in den Hafen benötigen Sie den Code in C ++, es ist viel besser, die ‚neuen‘ Betreiber zu verwenden.

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