c style casts oder c ++ style casts

21

Also, was benutzt du?

int anInt = (int)aFloat;

oder

int anInt = static_cast<int>(aFloat);
// and its brethren

Und was noch wichtiger ist, warum?

Bastibe
quelle

Antworten:

45

Verstehen Sie zunächst, dass diese Zeilen nicht gleichwertig sind .

int* anInt = (int*)aFloat; // is equivalent to

int* anInt = reinterpret_cast<int*>(aFloat); 

Was hier passiert, ist, dass der Programmierer den Compiler auffordert, alles zu tun, um die Besetzung vorzunehmen.

Der Unterschied ist wichtig, da bei Verwendung von static_cast nur ein "sicherer" Basistyp erforderlich ist, in den reinterpret_cast konvertiert werden kann, indem möglicherweise nur das gewünschte Speicherlayout auf den Speicher des angegebenen Objekts abgebildet wird.

Da der "Filter" nicht derselbe ist, ist die Verwendung einer bestimmten Besetzung klarer und sicherer als die Verwendung der C-Besetzung, wenn Sie sich auf den Compiler verlassen (oder auf die Laufzeitimplementierung, wenn Sie dynamic_cast verwenden), um zu erfahren, wo Sie etwas falsch gemacht haben , durch Umgehen von C cast und reinterepret_cast.

Nun, da dies klarer ist, gibt es noch eine andere Sache: static_cast, reinterpret_cast, const_cast und dynamic_cast sind einfacher zu suchen .

Und der letzte Punkt: Sie sind hässlich . Das ist gewollt. Möglicherweise fehlerhafter Code, Codegerüche, offensichtliche "Tricks", die Fehler erzeugen könnten, sind leichter zu verfolgen, wenn sie mit hässlichem Aussehen in Verbindung gebracht werden. Schlechter Code sollte hässlich sein .

Das ist "mit Absicht". Auf diese Weise kann der Entwickler erkennen, wo er die Dinge hätte besser machen können (indem er Abgüsse vollständig vermeidet, wenn sie nicht wirklich benötigt werden) und wo es in Ordnung ist, aber es wird im Code "dokumentiert", indem er es als hässlich "markiert".

Ein zweiter Grund für die Einführung der neuen Besetzung war, dass C-Besetzungen in einem Programm sehr schwer zu erkennen sind. Beispielsweise können Sie nicht bequem mit einem normalen Editor oder Textverarbeitungsprogramm nach Besetzungen suchen. Diese Unsichtbarkeit von Gipsabdrücken im C-Stil ist besonders bedauerlich, da sie so potenziell schädlich sind. Eine hässliche Operation sollte eine hässliche syntaktische Form haben. Diese Beobachtung war Teil des Grundes für die Wahl der Syntax für die Casts neuen Stils. Ein weiterer Grund war, dass die Darstellungen im neuen Stil der Schablonennotation entsprachen, sodass Programmierer ihre eigenen Darstellungen schreiben konnten, insbesondere zur Laufzeit überprüfte Darstellungen.

Vielleicht, weil static_cast so hässlich und relativ schwer zu tippen ist, ist es wahrscheinlicher, dass Sie zweimal darüber nachdenken, bevor Sie eines verwenden? Das wäre gut, denn in modernem C ++ sind Casts eigentlich meist vermeidbar.

Quelle: Bjarne Stroustrup (C ++ - Entwickler)

Klaim
quelle
2
Ich würde dies ablehnen, wenn ich noch ein paar Punkte hätte, aber leider kann ich nicht. c-style casts sind NICHT gleichbedeutend mit reinterpret_cast. Überlegen Sie reinterpret_cast<int>(double);. Es ist durchaus möglich, ein Double mit einer C-Besetzung in ein Int umzuwandeln, aber mit reinterpret_cast ist dies nicht möglich. Ich sehe, Timbo hat Sie bereits darauf hingewiesen, und Sie sagten, Sie würden es reparieren, aber vier Jahre später bleibt es falsch. Ich würde Sie trotzdem ablehnen, wenn dies behoben wäre, da es durchaus berechtigte Gründe gibt, eine Besetzung zu benötigen. Hier ist eine bessere Antwort: stackoverflow.com/a/332086/3878168
Yay295
36

C ++ - Casts sind restriktiver (drücken Sie Ihre Absichten also besser aus und erleichtern Sie die Codeüberprüfung usw.). Sie sind auch viel einfacher zu suchen, wenn Sie es jemals brauchen.

Bruce Stephens
quelle
10
... und sie werden eher das tun, was Sie vorhaben. ;-)
Macke
7
Und es gibt noch viel mehr zu tippen, was Ihnen einen weiteren Grund gibt, Ihre Texte korrekt zu schreiben, ohne dass ein Cast erforderlich ist.
Michael Kohne
7
Und sie sind als Feature hässlich und machen deutlich, wo im Code Verbesserungspunkte oder Sonderfälle zu finden sind, für die möglicherweise Dokumentation erforderlich ist. - edit: wow, ich habe gerade entdeckt, dass ich diese Frage auch beantwortet habe! XD
Klaim
Warum sollte ich jetzt nach ihnen suchen wollen?
Deduplizierer
@Deduplicator Es gibt viele Gründe, warum Sie wissen möchten, wo in einer Codebasis Besetzungen stattfinden. Zum Beispiel bei der Suche nach Fehlern, die mit dem Casting in Verbindung gebracht werden könnten (insbesondere bei der plattformübergreifenden Entwicklung).
Klaim,
13

Option C: Eine Besetzung im "C ++ - Stil", da sie nicht von einer Konstruktion zu unterscheiden ist:

int anInt = int(aFloat);

oder auch:

int anInt(aFloat);

Abgesehen von diesen trivialen Fällen mit Primitiven, die gut verstanden werden, bevorzuge ich x_casts gegenüber C-Casts. Dafür gibt es drei Gründe:

  • Sie definieren die Operation, die der Programmierer ausführen wollte, enger.

  • Sie können Aktionen ausführen, die C-Casts nicht können (insbesondere im Fall von dynamic_cast <>, bei dem ein Cross-Cast über Zweige einer Mehrfachvererbungskette ausgeführt werden kann).

  • Sie sind hässlich . Sie erklären lautstark, dass der Programmierer gegen das Typsystem arbeitet. In diesem Fall ist es eine gute Sache.

Kaz Dragon
quelle
7

Wenn Sie Code in C schreiben, verwenden Sie einen C-Cast. Wenn Sie in C ++ schreiben, verwenden Sie eine C ++ - Besetzung.

Während die meisten Castings die richtige Typensicherheit verletzen, sind die C ++ restriktiver und daher etwas weniger typensicher als bei einem C-Casting.

Ich kann es tolerieren, dass jemand (T *) NULL verwendet, um eine Überladung zu erzwingen ...

Goldesel
quelle
7

Ich habe ein paar Regeln für C / C ++ - Darstellungen:

  1. Das Deaktivieren einer Konstante muss immer mit a erfolgen const_cast. Aus offensichtlichen Gründen. Leider wurde meine Regel, eine Konstante zu entfernen, die dazu führt, dass die Tastatur nach oben greift und dem Programmierer den Finger bricht, nicht akzeptiert.
  2. Alle Spielereien im Bit-Manipulations-Stil, mit denen Programmierer vertraut sind, wenn sie sich auf das Metall konzentrieren, sollten verwendet werden reinterpret_cast. Es ist wirklich die Art von Besetzung, die C nicht hat: Stellen Sie sich vor, die Bits dieser ganzen Zahl seien die Bits eines Floats. Dies vermeidet Unannehmlichkeiten wie (int)(*(int*)(&floatVar)).
  3. Wenn Sie die Wörter " dynamic_cast" eingeben, beenden Sie die polymorphe Klassenhierarchie und das Design und werten Sie sie erneut aus. Bewerten Sie den Entwurf Ihrer Klassenhierarchie erneut, bis Sie diese Wörter löschen können.
  4. Kümmere dich nicht darum static_cast.

Die Argumentation hinter # 4 ist einfach, dass es egal ist. Die Umstände, die nicht in die anderen Regeln passen, sind entweder offensichtlich oder sehr niedrig. Eine verständliche Konvertierung einfacher Typen wie int-to-float sollte keine spezielle Syntax erfordern. Und wenn Sie unten in den tiefen, hässlichen Eingeweiden von etwas sind, dann sind Sie unten in den tiefen, hässlichen Eingeweiden von etwas. Es ist nicht nötig, die Aufmerksamkeit auf die Tatsache zu lenken, dass "hier sind Drachen", da die Zähne, Klauen und das Feuer es schon so ziemlich verraten haben.

Nicol Bolas
quelle
1
dynamic_castist ein perfekt gültiges Werkzeug. Selten nützlich, gebe ich zu, aber es ist weit entfernt vom Satan von Dingen wie globalen Variablen. In erster Linie habe ich Sie jedoch herabgestimmt, weil Sie die Frage , ob C-Casts verwendet werden oder nicht, nicht beantwortet haben .
DeadMG
2
@DeadMG: Ich habe über C-Besetzungen gesprochen. Der gesamte letzte Absatz rechtfertigt C-Besetzungen zugunsten von static_cast.
Nicol Bolas
"Leider wurde meine Regel, eine Konstante zu entfernen, die dazu führt, dass die Tastatur nach oben greift und dem Programmierer den Finger bricht, nicht akzeptiert." Technisch gesehen ist es für den Compiler rechtmäßig, dies zu ermöglichen. Wie es für den Compiler legal ist , Dämonen aus der Nase fliegen zu lassen .
Pharap,
3

Es kommt wirklich darauf an, mit welcher Sprache ich arbeite, denn Sie wissen, was sie sagen: In Rom sprechen Sie Roman. Wenn ich also in C programmiere, versuche ich, die C-Funktionen maximal zu nutzen, aber wenn ich in C ++ programmiere, verwende ich die C ++ - Funktionen maximal, auch wenn einige Leute diesen Ansatz aus diesem Grund nicht mögen Sie sagen, es macht den Code "weniger portabel", ich sage, dass es mich nicht interessiert, ich bin in C ++ und programmiere in C ++, und ich brauche einen vollständig C ++ kompatiblen Compiler, um Code zu kompilieren, sonst würde ich mit etwas anderem arbeiten an erster Stelle.

Coyote21
quelle
Es funktioniert nicht wirklich, C ++ - Casts in C zu verwenden ;-)
Steve314
3

static_cast usw. wurden aufgrund von Problemen mit den C-Darstellungen bei der Verwendung in Vorlagen erfunden. Wenn Sie eine Vorlage schreiben oder wenn der Code später möglicherweise in eine Vorlage konvertiert wird, empfiehlt es sich, Darstellungen im C ++ - Stil zu verwenden. Der Grund dafür ist, dass die C ++ - Darstellungen die Absicht besser ausdrücken und in Fällen, in denen C-Darstellungen das Falsche tun (bei bestimmten Typen als Vorlagenparameter), die erwarteten Ergebnisse liefern.

Abgesehen davon, sage ich, verwenden Sie C ++ - Casts, wenn Sie ein bestimmtes Problem haben, das diese benötigt - dynamic_cast ist das häufigste, aber selbst das ist wahrscheinlich nicht alltäglich.

Alles andere und eine Besetzung im C-Stil sind möglicherweise weniger unübersichtlich und tragen zur besseren Lesbarkeit bei, oder auch nicht, je nachdem, wie vertraut der Leser mit diesem Besetzungsstil heutzutage ist. Es ist aus meiner Sicht nicht wirklich wichtig, hauptsächlich eine persönliche Präferenzsache, aber wundern Sie sich nicht, wenn manche Leute den C-Stil nicht mögen.

Letzte Anmerkung: Wenn Sie so viele Casts benötigen, dass dies eine große Sache ist, machen Sie wahrscheinlich etwas anderes falsch. In einigen Fällen gibt es Ausnahmen, aber für die meisten High-Level-Codes sollten nicht viele (wenn überhaupt) Casts erforderlich sein.

Steve314
quelle