Bevor die Leute anfangen, dies als Dup zu markieren, habe ich Folgendes gelesen, von denen keines die Antwort liefert, nach der ich suche:
- C FAQ: Was ist falsch daran, den Rückgabewert von malloc zu geben?
- SO: Sollte ich den Rückgabewert von malloc () explizit umwandeln?
- SO: Unnötige Zeigerabdrücke in C.
- SO: Werfe ich das Ergebnis von Malloc?
Sowohl die C-FAQ als auch viele Antworten auf die obigen Fragen führen einen mysteriösen Fehler an, malloc
den der Rückgabewert des Castings verbergen kann. Keiner von ihnen gibt jedoch ein konkretes Beispiel für einen solchen Fehler in der Praxis. Achten Sie jetzt darauf, dass ich Fehler sagte , nicht Warnung .
Geben Sie nun den folgenden Code ein:
#include <string.h>
#include <stdio.h>
// #include <stdlib.h>
int main(int argc, char** argv) {
char * p = /*(char*)*/malloc(10);
strcpy(p, "hello");
printf("%s\n", p);
return 0;
}
Das Kompilieren des obigen Codes mit gcc 4.2 mit und ohne Umwandlung gibt dieselben Warnungen aus, und das Programm wird ordnungsgemäß ausgeführt und liefert in beiden Fällen dieselben Ergebnisse.
anon@anon:~/$ gcc -Wextra nostdlib_malloc.c -o nostdlib_malloc
nostdlib_malloc.c: In function ‘main’:
nostdlib_malloc.c:7: warning: incompatible implicit declaration of built-in function ‘malloc’
anon@anon:~/$ ./nostdlib_malloc
hello
Kann jemand ein bestimmtes Codebeispiel für einen Kompilierungs- oder Laufzeitfehler geben, der aufgrund des malloc
Rückgabewerts des Castings auftreten kann, oder ist dies nur eine urbane Legende?
Bearbeiten Ich bin auf zwei gut geschriebene Argumente zu diesem Thema gestoßen:
- Für das Casting: CERT-Hinweis: Das Ergebnis eines Funktionsaufrufs für die Speicherzuweisung wird sofort in einen Zeiger auf den zugewiesenen Typ umgewandelt
- Gegen Casting (404-Fehler vom 14.02.2012: Verwenden Sie die Internet Archive Wayback Machine- Kopie vom 27.01.2010. {18.03.2016: "Seite kann aufgrund von robots.txt nicht gecrawlt oder angezeigt werden."})
void
Zeigern kann der Code als C ++ kompiliert werden. Einige Leute sagen, dass dies eine Funktion ist, ich würde sagen, dass es ein Fehler ist;)malloc
Rückgabewerts des Castings : Casting in einenint*
64-Bit-Bogen.C
nicht markiertC++
(es handelt sich um zwei verschiedene Sprachen). Daher ist jede Diskussion (wie in einigen Antworten) für diese Frage nicht relevant.Antworten:
Sie erhalten keinen Compilerfehler , sondern eine Compilerwarnung . Wie die von Ihnen zitierten Quellen sagen (insbesondere die erste ), können Sie einen unvorhersehbaren Laufzeitfehler erhalten, wenn Sie die Besetzung ohne Einbeziehung verwenden
stdlib.h
.Der Fehler auf Ihrer Seite ist also nicht die Besetzung, sondern das Vergessen, sie einzuschließen
stdlib.h
. Compiler können davon ausgehen, dassmalloc
es sich um eine zurückgegebene Funktionint
handelt. Daher wird dervoid*
tatsächlich zurückgegebene Zeiger aufgrund der expliziten Umwandlungmalloc
inint
und dann in Ihren Zeigertyp konvertiert . Auf einigen Plattformen könnenint
Zeiger eine unterschiedliche Anzahl von Bytes belegen, sodass die Typkonvertierungen zu einer Beschädigung der Daten führen können.Glücklicherweise geben moderne Compiler Warnungen aus, die auf Ihren tatsächlichen Fehler hinweisen. Siehe die von
gcc
Ihnen angegebene Ausgabe: Sie werden gewarnt, dass die implizite Deklaration (int malloc(int)
) nicht mit der integrierten deklariert istmalloc
. Sogcc
scheint esmalloc
auch ohne zu wissenstdlib.h
.Das Auslassen der Besetzung, um diesen Fehler zu vermeiden, ist meistens die gleiche Begründung wie das Schreiben
anstatt
da letzteres zu einem schwerwiegenden Fehler führen könnte, wenn man verwirrt
=
und==
, während der erste zu einem Kompilierungsfehler führen würde. Ich persönlich bevorzuge den letzteren Stil, da er meine Absicht besser widerspiegelt und ich diesen Fehler nicht mache.Gleiches gilt für das Umwandeln des von zurückgegebenen Werts
malloc
: Ich bevorzuge es, explizit zu programmieren, und überprüfe im Allgemeinen, ob die Header-Dateien für alle von mir verwendeten Funktionen enthalten sind.quelle
stdlib.h
ist bereits ein Fehler für sich, selbst wenn Sie nur Warnungen "implizite Deklaration" erhalten.Eines der guten Argumente auf höherer Ebene gegen das Casting des Ergebnisses von
malloc
wird oft nicht erwähnt, obwohl es meiner Meinung nach wichtiger ist als die bekannten Probleme auf niedrigerer Ebene (wie das Abschneiden des Zeigers, wenn die Deklaration fehlt).Eine gute Programmierpraxis besteht darin, Code zu schreiben, der so typunabhängig wie möglich ist. Dies bedeutet insbesondere, dass Typnamen im Code so wenig wie möglich oder am besten gar nicht erwähnt werden sollten. Dies gilt für Casts (vermeiden Sie unnötige Casts), Typen als Argumente von
sizeof
(vermeiden Sie die Verwendung von Typnamen insizeof
) und im Allgemeinen alle anderen Verweise auf Typnamen.Typnamen gehören in Deklarationen. Typnamen sollten so weit wie möglich auf Deklarationen und nur auf Deklarationen beschränkt sein.
Unter diesem Gesichtspunkt ist dieses Codebit schlecht
und das ist viel besser
nicht einfach, weil es "das Ergebnis von nicht
malloc
umwandelt", sondern weil es typunabhängig ist (oder typunabhängig, wenn Sie es vorziehen), weil es sich automatisch an den Typ anpasstp
, mit dem deklariert wird, ohne dass ein Eingreifen von erforderlich ist der Nutzer.quelle
Es wird angenommen, dass nicht prototypisierte Funktionen zurückkehren
int
.Sie werfen also einen
int
auf einen Zeiger. Wenn Zeigerint
auf Ihrer Plattform breiter als s sind, ist dies ein sehr riskantes Verhalten.Außerdem betrachten manche Leute Warnungen als Fehler, dh Code sollte ohne sie kompiliert werden.
Persönlich denke ich, dass die Tatsache, dass Sie nicht in
void *
einen anderen Zeigertyp umwandeln müssen, eine Funktion in C ist, und betrachten Sie Code, der beschädigt werden muss.quelle
void*
.int
." - Meinst du, es ist möglich, den Rückgabetyp von nicht prototypisierten Funktionen zu ändern?#ifdef __cplusplus \nextern "C" { \n#endif static inline uint16_t swb(uint16_t a) {return ((a << 8) | ((a >> 8) & 0xFF); } \n#ifdef __cplusplus\n } \n#endif
. Warum Sie malloc in einer statischen Inline-Funktion aufrufen möchten, weiß ich wirklich nicht, aber Header, die in beiden funktionieren, sind kaum unbekannt.Wenn Sie dies beim Kompilieren im 64-Bit-Modus tun, wird Ihr zurückgegebener Zeiger auf 32 Bit abgeschnitten.
EDIT: Tut mir leid, dass ich zu kurz bin. Hier ist ein Beispielcodefragment für Diskussionszwecke.
Angenommen, der zurückgegebene Heap-Zeiger ist größer als das, was in einem int dargestellt werden kann, z. B. 0xAB00000000.
Wenn malloc keinen Prototyp für die Rückgabe eines Zeigers hat, befindet sich der zurückgegebene int-Wert zunächst in einem Register, in dem alle signifikanten Bits gesetzt sind. Jetzt sagt der Compiler: "Okay, wie konvertiere ich und int in einen Zeiger". Dies wird entweder eine Vorzeichenerweiterung oder eine Nullerweiterung der 32-Bit niedriger Ordnung sein, von der Malloc mitgeteilt wurde, dass sie durch Weglassen des Prototyps "zurückkehrt". Da int signiert ist, denke ich, dass die Konvertierung eine Vorzeichenerweiterung ist, die in diesem Fall den Wert in Null konvertiert. Mit einem Rückgabewert von 0xABF0000000 erhalten Sie einen Zeiger ungleich Null, der auch Spaß macht, wenn Sie versuchen, ihn zu dereferenzieren.
quelle
Eine wiederverwendbare Softwareregel:
Wenn Sie eine Inline-Funktion schreiben, in der malloc () verwendet wird, führen Sie ein explizites Typ-Casting durch (z. B. (char *)), um es auch für C ++ - Code wiederverwendbar zu machen. Andernfalls wird sich der Compiler beschweren.
quelle
malloc
/free
für beide möglicherweise besser als die Verwendungmalloc
in C undnew
C ++, insbesondere wenn Datenstrukturen zwischen C und C ++ gemeinsam genutzt werden Code und es besteht die Möglichkeit, dass ein Objekt in C-Code erstellt und in C ++ - Code freigegeben wird oder umgekehrt.Ein ungültiger Zeiger in C kann jedem Zeiger ohne explizite Umwandlung zugewiesen werden. Der Compiler gibt eine Warnung aus, kann jedoch in C ++ durch Typumwandlung
malloc()
in den entsprechenden Typ wiederverwendet werden . Ohne Typguss kann es auch in C verwendet werden , da C keine strenge Typprüfung ist . Da C ++ jedoch eine reine Typprüfung ist , ist es erforderlich, Castmalloc()
in C ++ einzugeben.quelle