Ich habe die Besetzung nur eingefügt, um die Missbilligung des hässlichen Lochs im Typsystem zu zeigen, wodurch Code wie das folgende Snippet ohne Diagnose kompiliert werden kann, obwohl keine Besetzungen verwendet werden, um die schlechte Konvertierung herbeizuführen:
double d;
void *p = &d;
int *q = p;
Ich wünschte, das gäbe es nicht (und es gibt es nicht in C ++) und so habe ich gegossen. Es repräsentiert meinen Geschmack und meine Programmierpolitik. Ich werfe nicht nur einen Zeiger, sondern effektiv einen Stimmzettel und treibe Dämonen der Dummheit aus . Wenn ich Dummheit nicht wirklich austreiben kann , dann lassen Sie mich zumindest den Wunsch mit einer Geste des Protests zum Ausdruck bringen.
In der Tat ist es eine gute Praxis, malloc
(und Freunde) mit Funktionen zu versehen, die zurückkehren unsigned char *
, und im Grunde nie void *
in Ihrem Code zu verwenden. Wenn Sie einen generischen Zeiger auf ein beliebiges Objekt benötigen, verwenden Sie ein char *
oder unsigned char *
und haben Casts in beide Richtungen. Die einzige Entspannung, die man sich vielleicht gönnen kann, ist die Verwendung von Funktionen wie memset
und memcpy
ohne Abgüsse.
Zum Thema Gießen und C ++ Kompatibilität, wenn Sie Ihren Code schreiben , so dass es kompiliert , da beide C und C ++ (in diesem Fall Sie haben den Rückgabewert zu werfen , malloc
wenn es um etwas anderes als die Zuordnung void *
), können Sie ein sehr hilfreichen tun Sache für sich selbst: Sie können Makros für das Casting verwenden, die beim Kompilieren als C ++ in Casts im C ++ - Stil übersetzt werden, beim Kompilieren als C ++ jedoch auf einen C-Cast reduzieren:
/* 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, grep
zeigt Ihnen eine einfache Suche in Ihrer Codebasis nach diesen Bezeichnern, wo sich alle Ihre Besetzungen befinden, sodass Sie überprüfen können, ob sie falsch sind.
Wenn Sie dann in Zukunft den Code regelmäßig mit C ++ kompilieren, wird die Verwendung einer geeigneten Besetzung erzwungen. Wenn Sie beispielsweise strip_qual
nur ein const
oder entfernen volatile
, das Programm sich jedoch so ändert, dass jetzt eine Typkonvertierung durchgeführt wird, erhalten Sie eine Diagnose, und Sie müssen eine Kombination von Casts verwenden, um die gewünschte Konvertierung zu erhalten.
Um Ihnen bei der Einhaltung dieser Makros zu helfen, verfügt der GNU C ++ (nicht C!) - Compiler über eine schöne Funktion: eine optionale Diagnose, die für alle Vorkommen von C-Casts erstellt wird.
-Wold-Style-Cast (nur C ++ und Objective-C ++)
Warnen Sie, wenn ein Cast im alten Stil (C-Stil) verwendet wird, der nicht leer ist
innerhalb eines C ++ - Programms. Die neuen Casts (dynamic_cast,
static_cast, reinterpret_cast und const_cast) sind weniger anfällig
zu unbeabsichtigten Effekten und viel einfacher zu suchen.
Wenn Ihr C-Code als C ++ kompiliert wird, können Sie mit dieser -Wold-style-cast
Option alle Vorkommen der (type)
Casting-Syntax ermitteln, die sich möglicherweise in den Code eingeschlichen haben, und diese Diagnose weiterverfolgen, indem Sie sie durch eine geeignete Auswahl aus den oben genannten Makros (oder a) ersetzen Kombination, falls erforderlich).
Diese Behandlung von Konvertierungen ist die größte eigenständige technische Rechtfertigung für die Arbeit in einem "sauberen C": der kombinierte C- und C ++ - Dialekt, der wiederum das Casting des Rückgabewerts von technisch rechtfertigt malloc
.