Unterschied zwischen static_cast und C-Style Cast (int) ?
-
int i; double d; i = static_cast<int>(d); i = (int)d;
Was ist der Unterschied zwischen static_cast<int>(d) und (int)d ?
Kann mir das jemand bitte erklären?
Was passiert intern?
MfG U.
-
Im besten Fall kein Unterschied.
Im schlechten Fall wird ein der c-cast zu einem reinterpret_cast und das ohne irgendeine Warnung.
Der cast Typ wird beim c-cast automatisch vom compiler gewählt und bei den c++ casts macht das der Entwickler bewusst.
-
static_cast ist:
* Im Code schneller und direkter als Cast zu erkennen
* Erlaubt keine Bit-Knispel-Casts, die nicht portabel sind. Dafür muss man reinterpret_cast benutzen
-
du kannst dir die regel so merken, dass der C-cast den reinterpret_cast am nächsten kommt, da wird also der datentyp uminterpretiert, was natürlich bei zeigern (32bit oder neuerdings ja auch 64 :)) sehr praktisch ist, aber bei anderen sachen ist entweder static_cast oder const_cast zu empfehlen.
-
Unterschiedsucher schrieb:
Was ist der Unterschied zwischen static_cast<int>(d) und (int)d ?
Es gibt keine (semantischen) Unterschied zwischen beiden Casts wenn beide zulässig sind. Ein C-Style Cast kann an Stellen zulässig sein, wo static_cast nicht anwendbar ist (dort, wo wir const_cast und/oder reinterpret_cast verwenden müssen) - und darin liegt die Gefahr, denn welche Formen zulässig sind, ist dem Ausdruck selbst oft nicht zu entnehmen.
Hauptsächlich - aber nicht nur - betrifft dies Casts, bei denen ein Zeigertyp involviert ist.
Ein interessanter Fall (durchaus mit praktischer Relevanz)struct A { ... }; struct B; B* B_from_A1(A* p) { return (B*)p; } struct B : A { ... }; B* B_from_A2(A* p) { return (B*)p; }
Beide Funktionen führen völlig verschiedene Dinge aus.
Nebenbei bemerkt hat reinterpret_cast nichts mit "bit-schnipsel-Casts" zu tun (und es für diese Zwecke zu benutzen ist in der Regel sowieso undefiniert). Und "uminterpretieren" ist auch keine brauchbare Definition.
-
ber bei anderen sachen ist entweder static_cast oder const_cast zu empfehlen.
const_cast aber nur gaaaaaaaanz selten. eigentlich eher nicht.
-
camper schrieb:
Nebenbei bemerkt hat reinterpret_cast nichts mit "bit-schnipsel-Casts" zu tun (und es für diese Zwecke zu benutzen ist in der Regel sowieso undefiniert). Und "uminterpretieren" ist auch keine brauchbare Definition.
Es wäre dann nett, wenn Du dazu gleich eine brauchbare Definition nebst dem korrekten Sinn und Gebrauch liefern würdest.
-
camper schrieb:
Und "uminterpretieren" ist auch keine brauchbare Definition.
ist sicherlich nicht ganz fein, aber erklärt seinen zweck, und ich muss meinem vorredner zustimmen, dass wenn du schon bemängelst dann definiere bitte besser.^^ da es heir anscheinend ein verständnisproblem gibt, sollte man auch etwas einfachere definitionen liefern.
und den zweck dachte hätte ich erklärt, meistens im zusammhang mit zeigern.^^ für die meisten anderen casts (die, wo casten logisch möglich ist, z. b. non lfoat zu int) nutztb man static_cast. mit diser regel fährt man auch gut, nur wenn man an die grenzen stößt befasst man sich tiefer damit.
-
camper schrieb:
Beide Funktionen führen völlig verschiedene Dinge aus.
Wie meinst du das ?
So wie ich das sehe, machen beide Funktionen exakt den gleichen Murks. Sie geben einen Zeiger zurück, der auf einen undefinierten Speicherplatz zeigt:
struct A { int a; }; struct B; B* B_from_A1(A* p) { return (B*)p; } struct B : A { int b; }; B* B_from_A2(A* p) { return (B*)p; } int main() { struct A a = {88}; struct B* pb = B_from_A1(&a); cout << pb->a << endl; cout << pb->b << endl; // nicht definiert pb = B_from_A2 ( &a ); cout << pb->b << endl; cout << pb->a << endl; // nicht definiert return 0; }
Tachyon schrieb:
Es wäre dann nett, wenn Du dazu gleich eine brauchbare Definition nebst dem korrekten Sinn und Gebrauch liefern würdest.
Es wäre auch nett, wenn du mal ein Beispiel für einen Bit-Knispel-Cast liefern würdest.
-
Unterschiedsucher schrieb:
Wie meinst du das ?
So wie ich das sehe, machen beide Funktionen exakt den gleichen Murks. Sie geben einen Zeiger zurück, der auf einen undefinierten Speicherplatz zeigt:
Dein Programm hat undefiniertes Verhalten und ist folglich ungeeignet, den Unterschied zwischen beiden Funktionen zu demonstrieren. Tatsächlich ist das Ergebnis der ersten Funktion nicht undefiniert (bzw. ein Zeiger auf undefinierten Speicher - was immer das bedeuten mag), sondern ein Zeiger, der auf das gleiche Objekt, wie das Argument zeigt, nur mit anderem Typ (sofern wir als plausible Randbedingung annehmen, das Alignment kein Rolle spielt).
Undefiniert sind daher beide folgenden Zugriffe auf die Member a und b, da das Objekt an dieser Stelle eben tatsächlich kein Objekt vom Typ B ist (und A und B nicht beide PODs sind, andernfalls könnte ggf. strukturelle Äquivalenz helfen). Im Gegensatz dazu ist das Ergebnis der zweiten Funktion unmittelbar undefiniert.
Für ein etwas überzeugenderes Beispiel (dass der Einfachheit halber auch undefiniertes Verhalten hat, aber praktisch einfacher zu demonstrieren ist), müssen wir das Ganze etwas verändern:struct A { int a; }; struct B; B* B_from_A1(A* p) { return (B*)p; } struct Foo { int foo; }; struct Bar { int bar; }; struct B : Foo, A, Bar { int b; }; B* B_from_A2(A* p) { return (B*)p; } int main() { B x; x.a = 0; x.b = 1; x.foo = 2; x.bar = 3; A* p = &x; B* pb = B_from_A1(p); // jetzt wird es 4x problematisch cout << pb->a << endl; cout << pb->b << endl; cout << pb->foo << endl; cout << pb->bar << endl; pb = B_from_A2 (p); cout << pb->a << endl; cout << pb->b << endl; cout << pb->foo << endl; cout << pb->bar << endl; }
-
Unterschiedsucher schrieb:
Tachyon schrieb:
Es wäre dann nett, wenn Du dazu gleich eine brauchbare Definition nebst dem korrekten Sinn und Gebrauch liefern würdest.
Es wäre auch nett, wenn du mal ein Beispiel für einen Bit-Knispel-Cast liefern würdest.
Mit Bit-Knispel-Cast meine ich die üblichen Pointer-Typ-A->Pointer-Typ-B->Pointer-Typ-A-Casts die man ja in der Regel nicht ausführt, ohne vorher auf dem Pointer-Typ-B rumzurühren. Dabei werden, je nach Intention des Programmieres, die Bits für die Dereferenz von Pointer-Typ-B völlig anders interpetiert, als bei der Dereferenz von Pointer-Typ-A.
Pointer-Typ->Integer-Casts werden auch oft zum Bit-Knispeln benutzt, z.B. mittels bitweisem xor zum Generieren von Hash-Tabellen.
Sowas meinte ich mit Bit-Knispeln.
-
Mit anderen Worten:
Intern passiert das gleiche.Danke.
MFG U.
-
@Camper:
Ich vermisse immer noch eine Antwort auf meine Frage bzw. die Argumentation für Deine Aussage.
-
Tachyon schrieb:
Pointer-Typ->Integer-Casts werden auch oft zum Bit-Knispeln benutzt, z.B. mittels bitweisem xor zum Generieren von Hash-Tabellen.
Sowas meinte ich mit Bit-Knispeln.Dagegen ist nichts einzuwenden.
Tachyon schrieb:
Mit Bit-Knispel-Cast meine ich die üblichen Pointer-Typ-A->Pointer-Typ-B->Pointer-Typ-A-Casts die man ja in der Regel nicht ausführt, ohne vorher auf dem Pointer-Typ-B rumzurühren. Dabei werden, je nach Intention des Programmieres, die Bits für die Dereferenz von Pointer-Typ-B völlig anders interpetiert, als bei der Dereferenz von Pointer-Typ-A.
Das Resultat der Konvertierung eines Objektzeigers (andere Zeigertypen brauchen wir hier nicht zu betrachten) in einen anderen Objektzeiger ist ein Zeiger, der auf das gleiche Objekt wie der ursprüngliche Zeiger zeigt - vorausgesetzt, dieses Objekt ist hinreichend ausgerichtet. Nullpointer werden in Nullpointer konvertiert. Insoweit besteht kein Problem. Problematisch ist die Aussage über das, was beim Dereferenzieren (genauer: beim Benutzen des Wertes des Objekts über den dereferenzierten Zeiger) passiert, ich verweise der Schreibfaulheit wegen mal hierauf: union problem, grundsätzliche Unterschiede bestehen hier zwischen C und C++ nicht.
"Bit-Schnipsel-Casts" funktionieren (größtenteils) nicht. Die wenigen definierten Fälle fallen kaum unter die Rubrik des Völlig-anders-Interpretierens.
Definierte Anwendungen von "Bit-Schnipseln" müssen Werte zunächst kopieren - ein memcpy aber erfordert keinen expliziten Cast (ja, mit std::copy wäre ein reinterpret_cast nach char* & co. ggf. nötig - aber std::copy ist nicht zwingend)