834 Stimmen

Warum static_cast<int>(x) anstelle von (int)x verwenden?

Ich habe gehört, dass die static_cast Funktion sollte dem Casting im Stil von C oder einfachen Funktionen vorgezogen werden. Stimmt das? Und warum?

46 Stimmen

Einspruch, Euer Ehren, gefragt und beantwortet .

35 Stimmen

Ich stimme nicht zu, diese andere Frage war über die Beschreibung der Unterschiede zwischen casts in C++ eingeführt. Diese Frage ist über die wirkliche Nützlichkeit von static_cast, die etwas anders ist.

2 Stimmen

Wir könnten die beiden Fragen sicherlich zusammenführen, aber was wir in diesem Thread beibehalten müssten, ist der Vorteil der Verwendung von Funktionen gegenüber dem Casting im C-Stil, der derzeit nur in einer einzeiligen Antwort im anderen Thread erwähnt wird, ohne dass darüber abgestimmt wurde.

752voto

Euro Micelli Punkte 32040

Der Hauptgrund dafür ist, dass die klassischen C-Casts keinen Unterschied machen zwischen dem, was wir als static_cast<>() , reinterpret_cast<>() , const_cast<>() y dynamic_cast<>() . Diese vier Dinge sind völlig unterschiedlich.

A static_cast<>() ist normalerweise sicher. Es gibt eine gültige Konvertierung in der Sprache oder einen geeigneten Konstruktor, der dies möglich macht. Das einzige Mal, dass es ein wenig riskant ist, ist, wenn man auf eine geerbte Klasse zurückgreift; man muss sicherstellen, dass das Objekt tatsächlich der Nachkomme ist, für den man es hält, und zwar mit Mitteln außerhalb der Sprache (z. B. einem Flag im Objekt). A dynamic_cast<>() ist sicher, solange das Ergebnis überprüft wird (Zeiger) oder eine mögliche Ausnahme berücksichtigt wird (Verweis).

A reinterpret_cast<>() (oder ein const_cast<>() ) ist dagegen immer gefährlich. Man sagt dem Compiler: "Vertrau mir: Ich weiß, das sieht nicht aus wie ein foo (das sieht so aus, als ob es nicht veränderbar ist), aber es ist".

Das erste Problem ist, dass es fast unmöglich ist, zu sagen, welche in einem C-ähnlichen Cast auftreten wird, ohne sich große und verstreute Codestücke anzusehen und alle Regeln zu kennen.

Gehen wir von diesen aus:

class CDerivedClass : public CMyBase {...};
class CMyOtherStuff {...} ;

CMyBase  *pSomething; // filled somewhere

Diese beiden werden auf die gleiche Weise zusammengestellt:

CDerivedClass *pMyObject;
pMyObject = static_cast<CDerivedClass*>(pSomething); // Safe; as long as we checked

pMyObject = (CDerivedClass*)(pSomething); // Same as static_cast<>
                                     // Safe; as long as we checked
                                     // but harder to read

Schauen wir uns jedoch diesen fast identischen Code an:

CMyOtherStuff *pOther;
pOther = static_cast<CMyOtherStuff*>(pSomething); // Compiler error: Can't convert

pOther = (CMyOtherStuff*)(pSomething);            // No compiler error.
                                                  // Same as reinterpret_cast<>
                                                  // and it's wrong!!!

Wie Sie sehen können, ist es nicht einfach, zwischen den beiden Situationen zu unterscheiden, ohne viel über die beteiligten Klassen zu wissen.

Das zweite Problem ist, dass die C-Würfe zu schwer zu finden sind. In komplexen Ausdrücken kann es sehr schwierig sein, die C-ähnlichen Besetzungen zu erkennen. Es ist praktisch unmöglich, ein automatisiertes Werkzeug zu schreiben, das Casts im C-Stil aufspüren muss (z. B. ein Suchwerkzeug), ohne ein vollwertiges C++-Compiler-Frontend. Andererseits ist es einfach, nach "static_cast<" oder "reinterpret_cast<" zu suchen.

pOther = reinterpret_cast<CMyOtherStuff*>(pSomething);
      // No compiler error.
      // but the presence of a reinterpret_cast<> is 
      // like a Siren with Red Flashing Lights in your code.
      // The mere typing of it should cause you to feel VERY uncomfortable.

Das bedeutet nicht nur, dass Würfe im C-Stil gefährlicher sind, sondern auch, dass es viel schwieriger ist, sie alle zu finden und sicherzustellen, dass sie korrekt sind.

38 Stimmen

Sie sollten nicht verwenden static_cast um eine Vererbungshierarchie abzustufen, sondern vielmehr dynamic_cast . Dies ergibt entweder den Null-Zeiger oder einen gültigen Zeiger.

52 Stimmen

@David Thornley: Ich stimme zu, normalerweise. Ich denke, ich habe die Vorbehalte gegen die Verwendung von static_cast in dieser Situation. dynamic_cast mag sicherer sein, ist aber nicht immer die beste Option. Manchmal muss man wissen dass ein Zeiger auf einen bestimmten Subtyp zeigt, und zwar mit für den Compiler undurchsichtigen Mitteln, und ein static_cast ist schneller. Zumindest in einigen Umgebungen, dynamic_cast erfordert optionale Compilerunterstützung und Laufzeitkosten (Aktivierung von RTTI), und Sie möchten es vielleicht nicht nur für ein paar Prüfungen aktivieren, die Sie selbst durchführen können. Die RTTI von C++ ist nur eine mögliche Lösung für das Problem.

23 Stimmen

Ihre Behauptung über C-Abgüsse ist falsch. Alle C-Casts sind Wertumwandlungen, ungefähr vergleichbar mit C++ static_cast . Das C-Äquivalent von reinterpret_cast es *(destination_type *)& d.h. die Adresse des Objekts nehmen, diese Adresse in einen Zeiger auf einen anderen Typ umwandeln und dann dereferenzieren. Außer im Fall von Zeichentypen oder bestimmten Strukturtypen, für die C das Verhalten dieses Konstrukts definiert, führt es im Allgemeinen zu undefiniertem Verhalten in C.

130voto

Karl Punkte 3104

Ein pragmatischer Tipp: Sie können leicht nach dem Schlüsselwort static_cast in Ihrem Quellcode suchen, wenn Sie vorhaben, das Projekt aufzuräumen.

8 Stimmen

Sie können mit den Klammern auch suchen, obwohl wie "(int)" aber gute Antwort und gültigen Grund, C++-Stil Casting verwenden.

8 Stimmen

@Mike, der falsch-positive Ergebnisse findet - eine Funktionsdeklaration mit einem einzigen int Parameter.

1 Stimmen

Dies kann zu falsch-negativen Ergebnissen führen: Wenn Sie eine Codebasis durchsuchen, in der Sie nicht der einzige Autor sind, werden Sie keine C-Style-Casts finden, die andere aus bestimmten Gründen eingeführt haben könnten.

121voto

Hossein Punkte 21448

Kurz gesagt :

  1. static_cast<>() gibt Ihnen eine Kompilierzeitüberprüfungsmöglichkeit, C-Style cast nicht.
  2. static_cast<>() kann leicht erkannt werden überall in einem C++-Quellcode zu erkennen; im Gegensatz dazu ist der C_Style-Cast schwerer zu erkennen.
  3. Intentionen lassen sich mit C++-Casts viel besser vermitteln.

Mehr Erläuterung :

Der statische Cast führt Konvertierungen zwischen kompatible Typen . Sie ähnelt dem C-Style Cast, ist aber restriktiver. Ein Beispiel, der C-Style-Cast würde einem Integer-Zeiger erlauben, auf ein Char zu zeigen.

char c = 10;       // 1 byte
int *p = (int*)&c; // 4 bytes

Da dies zu einem 4-Byte-Zeiger führt, der auf 1 Byte des zugewiesenen Speicher zeigt, wird das Schreiben auf diesen Zeiger entweder einen Laufzeitfehler verursachen oder überschreibt einen angrenzenden Speicherbereich.

*p = 5; // run-time error: stack corruption

Im Gegensatz zum Cast im C-Stil erlaubt der statische Cast dem Compiler zu prüfen, ob die Datentypen von Zeiger und Pointee kompatibel sind, was es dem Programmierer ermöglicht, diese falsche Zeigerzuweisung während der Kompilierung zu erkennen.

int *q = static_cast<int*>(&c); // compile-time error

Lesen Sie mehr darüber:
Was ist der Unterschied zwischen static_cast<> und C-Stil Casting
y
Regelmäßige Besetzung vs. statische Besetzung vs. dynamische Besetzung

30 Stimmen

Ich bin nicht der Meinung, dass static_cast<>() ist besser lesbar. Ich meine, manchmal es ist, aber die meiste Zeit - vor allem bei einfachen Integer-Typen - ist es einfach schrecklich und unnötig langatmig. Ein Beispiel: Dies ist eine Funktion, die die Bytes eines 32-Bit-Worts vertauscht. Es wäre fast unmöglich, sie mit static_cast<uint##>() wirft, ist aber recht einfach zu verstehen, wenn man (uint##) wirft. Bild des Codes: imgur.com/NoHbGve

4 Stimmen

@ToddLehman: Danke, aber ich habe nicht gesagt always entweder. (aber meistens ja) Es gibt sicherlich Fälle, in denen die C-Form viel besser lesbar ist. Das ist einer der Gründe, warum C-Stil Casting ist immer noch leben und treten in C++ imho. :) Übrigens, das war ein sehr schönes Beispiel

15 Stimmen

Der Code von @ToddLehman in diesem Bild verwendet zwei verkettete Würfe ( (uint32_t)(uint8_t) ), um zu erreichen, dass alle Bytes außer dem niedrigsten zurückgesetzt werden. Dafür gibt es bitweise und ( 0xFF & ). Die Verwendung von Würfen verschleiert die Absicht.

35voto

Dusty Campbell Punkte 3098

Die Frage ist größer als nur mit entweder static_cast oder C-Stil Casting, weil es verschiedene Dinge, die passieren, wenn mit C-Stil Casts. Die C++-Casting-Operatoren sollen diese Operationen expliziter machen.

Oberflächlich betrachtet scheinen static_cast und Casts im C-Stil dasselbe zu sein, z. B. beim Casting eines Wertes in einen anderen:

int i;
double d = (double)i;                  //C-style cast
double d2 = static_cast<double>( i );  //C++ cast

In beiden Fällen wird der Integer-Wert in einen Double-Wert umgewandelt. Bei der Arbeit mit Zeigern werden die Dinge jedoch komplizierter. einige Beispiele:

class A {};
class B : public A {};

A* a = new B;
B* b = (B*)a;                                  //(1) what is this supposed to do?

char* c = (char*)new int( 5 );                 //(2) that weird?
char* c1 = static_cast<char*>( new int( 5 ) ); //(3) compile time error

In diesem Beispiel ist (1) vielleicht in Ordnung, weil das Objekt, auf das A zeigt, in Wirklichkeit eine Instanz von B ist. Aber was ist, wenn man zu diesem Zeitpunkt im Code nicht weiß, auf was A tatsächlich zeigt? (2) ist vielleicht völlig legal (man will nur ein Byte der Ganzzahl betrachten), aber es könnte auch ein Fehler sein, in dem Fall wäre eine Fehlermeldung schön, wie (3). Die C++-Casting-Operatoren sollen diese Probleme im Code aufdecken, indem sie, wenn möglich, Fehler zur Kompilier- oder Laufzeit liefern.

Für striktes "Value Casting" können Sie also static_cast verwenden. Wenn Sie ein polymorphes Casting von Zeigern während der Laufzeit wünschen, verwenden Sie dynamic_cast. Wenn Sie wirklich auf Typen verzichten wollen, können Sie reintrepret_cast verwenden. Und um const einfach aus dem Fenster zu werfen, gibt es const_cast.

Sie machen den Code nur deutlicher, damit es so aussieht, als wüssten Sie, was Sie tun.

28voto

DrPizza Punkte 17330

static_cast bedeutet, dass Sie nicht versehentlich const_cast o reinterpret_cast was eine gute Sache ist.

4 Stimmen

Weitere (wenn auch eher geringfügige) Vorteile gegenüber dem C-Stil sind, dass es mehr auffällt (etwas potentiell Schlechtes zu tun, sollte hässlich aussehen) und dass es leichter zu greppen ist.

4 Stimmen

Die Grep-Fähigkeit ist meiner Meinung nach immer von Vorteil.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X