Ich habe den Cast nur eingefügt, um zu zeigen, dass ich die hässliche Lücke im Typsystem missbillige, die es ermöglicht, dass Code wie der folgende Schnipsel ohne Diagnose kompiliert werden kann, obwohl keine Casts verwendet werden, um die schlechte Konvertierung zu verursachen:
double d;
void *p = &d;
int *q = p;
Ich wünschte, das gäbe es nicht (und in C++ gibt es das auch nicht), und so habe ich gecastet. Es repräsentiert meinen Geschmack und meine Programmierpolitik. Ich werfe nicht nur einen Zeiger, sondern gebe tatsächlich einen Stimmzettel ab, und Dämonen der Dummheit austreiben . Wenn ich nicht kann eigentlich die Dummheit austreiben dann lassen Sie mich wenigstens den Wunsch dazu mit einer Geste des Protests zum Ausdruck bringen.
In der Tat ist es eine gute Praxis, die malloc
(und Freunde) mit Funktionen, die Folgendes zurückgeben unsigned char *
und grundsätzlich nie zu verwenden void *
in Ihrem Code. Wenn Sie einen generischen Zeiger auf ein beliebiges Objekt benötigen, verwenden Sie eine char *
o unsigned char *
und haben Würfe in beide Richtungen. Die einzige Entspannung, die man sich gönnen kann, ist vielleicht die Verwendung von Funktionen wie memset
y memcpy
ohne Gipsabdrücke.
Zum Thema Casting und C++-Kompatibilität: Wenn Sie Ihren Code so schreiben, dass er sowohl in C als auch in C++ kompilierbar ist (in diesem Fall müssen Sie müssen wird der Rückgabewert von malloc
wenn sie etwas anderem zugewiesen wird als void *
), können Sie eine sehr hilfreiche Sache für sich selbst tun: Sie können Makros für Casts verwenden, die zu C++-Stil Casts übersetzen, wenn als C++ kompiliert, aber zu einem C-Cast reduzieren, wenn als C kompiliert:
/* 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, dann ist eine einfache grep
Die Suche nach diesen Bezeichnern in Ihrer Codebasis zeigt Ihnen, wo sich alle Besetzungen befinden, so dass Sie überprüfen können, ob eine von ihnen falsch ist.
Wenn Sie den Code dann regelmäßig mit C++ kompilieren, wird er die Verwendung eines geeigneten Casts erzwingen. Zum Beispiel, wenn Sie strip_qual
nur zum Entfernen einer const
o volatile
aber das Programm ändert sich so, dass nun eine Typkonvertierung erforderlich ist, erhalten Sie eine Diagnose, und Sie müssen eine Kombination von Casts verwenden, um die gewünschte Konvertierung zu erhalten.
Um Ihnen zu helfen, diese Makros einzuhalten, hat der GNU C++ (nicht C!) Compiler eine wunderbare Funktion: eine optionale Diagnose, die für alle Vorkommen von C-Style Casts erzeugt wird.
-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 Ihr C-Code als C++ kompiliert wird, können Sie Folgendes verwenden -Wold-style-cast
um alle Vorkommen des Wortes (type)
Gießsyntax, die sich in den Code einschleichen kann, und folgen Sie diesen Diagnosen, indem Sie sie durch eine geeignete Auswahl aus den oben genannten Makros (oder eine Kombination, falls erforderlich) ersetzen.
Diese Behandlung von Konvertierungen ist die größte eigenständige technische Rechtfertigung für das Arbeiten in "Clean C": dem kombinierten C- und C++-Dialekt, der wiederum technisch das Casting des Rückgabewerts von malloc
.
35 Stimmen
stackoverflow.com/q/7545365/168175
9 Stimmen
Gussformen sind böse. Ich sehe so viele Abdrücke im Code, die nur das Ergebnis einer schlechten Programmierpraxis sind. Wann immer Sie einen Cast einfügen müssen, sollten Sie sich als erstes fragen, was hier falsch ist. Ist alles so deklariert, wie es sein sollte? Wenn ja, wäre kein Cast erforderlich, also ist etwas falsch deklariert. Wenn Sie wirklich etwas auf niedriger Ebene mit einzelnen Bytes in einem int oder so tun müssen, ziehen Sie eine Union in Betracht, um auf sie zuzugreifen. Das wird sie genau richtig deklarieren. Als Faustregel gilt: Fügen Sie sie nicht ein, es sei denn, der Compiler beschwert sich. Dann vermeiden Sie sie. Dieses Beispiel wird sich nicht beschweren. void pointer wird zu jedem Typ promoten.
2 Stimmen
@HansLepoeter in C++ sind diese für malloc erforderlich, was meine Vermutung stützt, dass damit etwas nicht stimmt