reinterpret_cast-Konvertierung
Konvertiert zwischen Typen durch Neudefinition des zugrunde liegenden Bitmusters.
Inhalt |
[bearbeiten] Syntax
reinterpret_cast< Zieltyp >( Ausdruck ) |
|||||||||
Gibt einen Wert vom Typ Zieltyp zurück.
[bearbeiten] Erklärung
Im Gegensatz zu static_cast, aber wie const_cast, kompiliert der reinterpret_cast-Ausdruck nicht zu CPU-Instruktionen (außer bei der Konvertierung zwischen Ganzzahlen und Zeigern oder zwischen Zeigern auf obskuren Architekturen, bei denen die Zeigerdarstellung von ihrem Typ abhängt). Er ist hauptsächlich eine Direktive zur Kompilierungszeit, die den Compiler anweist, den Ausdruck so zu behandeln, als hätte er den Typ Zieltyp.
Nur die folgenden Konvertierungen können mit reinterpret_cast durchgeführt werden, es sei denn, solche Konvertierungen entfernen constness (oder Volatilität).
static_cast oder implizite Konvertierung sollten für diesen Zweck verwendet werden.|
4) Jeder Wert vom Typ std::nullptr_t, einschließlich nullptr, kann in jeden integralen Typ konvertiert werden, als ob er (void*)0 wäre, aber kein Wert, nicht einmal nullptr, kann in std::nullptr_t konvertiert werden: static_cast sollte für diesen Zweck verwendet werden.
|
(seit C++11) |
T1* kann in einen anderen Objektzeigertyp cv T2* konvertiert werden. Dies ist exakt äquivalent zu static_cast<cv T2*>(static_cast<cv void*>(Ausdruck)) (was impliziert, dass sich der Wert des Zeigers nicht ändert, wenn die Ausrichtung von T2 nicht strenger ist als die von T1, und die Konvertierung des resultierenden Zeigers zurück in seinen ursprünglichen Typ den ursprünglichen Wert ergibt). In jedem Fall darf der resultierende Zeiger nur sicher dereferenziert werden, wenn der dereferenzierte Wert typzugänglich ist.T1 kann in eine Referenz auf einen anderen Typ T2 konvertiert werden. Das Ergebnis ist das von *reinterpret_cast<T2*>(p), wobei p ein Zeiger vom Typ "Zeiger auf T1" auf das Objekt oder die Funktion ist, auf die der Ausdruck verweist. Kein temporäres Objekt wird materialisiert oder(seit C++17) erstellt, keine Kopie wird gemacht, keine Konstruktoren oder Konvertierungsfunktionen werden aufgerufen. Die resultierende Referenz kann nur sicher aufgerufen werden, wenn sie typzugänglich ist.dlsym gefordert) kann ein Funktionszeiger in void* oder einen anderen Objektzeiger konvertiert werden, oder umgekehrt. Wenn die Implementierung Konvertierungen in beide Richtungen unterstützt, ergibt die Konvertierung in den ursprünglichen Typ den ursprünglichen Wert. Andernfalls kann der resultierende Zeiger nicht sicher dereferenziert oder aufgerufen werden.T1 kann in einen Zeiger auf ein anderes Objektmitglied einer anderen Klasse T2 konvertiert werden. Wenn die Ausrichtung von T2 nicht strenger ist als die von T1, ergibt die Konvertierung zurück in den ursprünglichen Typ T1 den ursprünglichen Wert, andernfalls kann der resultierende Zeiger nicht sicher verwendet werden.Wie bei allen Cast-Ausdrücken ist das Ergebnis
- ein lvalue, wenn Zieltyp ein lvalue-Referenztyp ist oder ein rvalue-Referenztyp auf eine Funktion(seit C++11);
|
(seit C++11) |
- sonst ein prvalue.
[bearbeiten] Typ-Aliasing
[bearbeiten] Typ-Zugriff
Wenn ein Typ T_ref ähnlich zu einem der folgenden Typen ist, ist ein Objekt mit dem dynamischen Typ T_obj durch ein lvalue(bis C++11)glvalue(seit C++11) vom Typ T_ref *typzugänglich*
- char
- unsigned char
|
(seit C++17) |
-
T_obj - der vorzeichenbehaftete oder vorzeichenlose Typ, der
T_objentspricht
Wenn ein Programm versucht, den gespeicherten Wert eines Objekts durch ein lvalue(bis C++11)glvalue(seit C++11) zu lesen oder zu ändern, durch das es nicht typzugänglich ist, ist das Verhalten undefiniert.
Diese Regel ermöglicht eine typbasierte Alias-Analyse, bei der ein Compiler annimmt, dass der Wert, der über ein glvalue eines Typs gelesen wird, nicht durch eine Schreiboperation auf ein glvalue eines anderen Typs geändert wird (vorbehaltlich der oben genannten Ausnahmen).
Beachten Sie, dass viele C++-Compiler diese Regel als nicht standardmäßige Spracherweiterung lockern, um den Zugriff auf den inaktiven Member einer union mit falschem Typ zu gestatten (ein solcher Zugriff ist in C nicht undefiniert).
[bearbeiten] Aufrufkompatibilität
Wenn eine der folgenden Bedingungen erfüllt ist, ist ein Typ T_call *aufrufkompatibel* mit einem Funktionstyp T_func
-
T_callist derselbe Typ wieT_func.
|
(seit C++17) |
Wenn eine Funktion über einen Ausdruck aufgerufen wird, dessen Funktionstyp nicht aufrufkompatibel mit dem Typ der Definition der aufgerufenen Funktion ist, ist das Verhalten undefiniert.
[bearbeiten] Anmerkungen
Unter der Annahme, dass die Ausrichtungsanforderungen erfüllt sind, ändert ein reinterpret_cast den Wert eines Zeigers nicht, außer in einigen wenigen begrenzten Fällen, die zeigerinterkonvertierbare Objekte betreffen.
struct S1 { int a; } s1; struct S2 { int a; private: int b; } s2; // not standard-layout union U { int a; double b; } u = {0}; int arr[2]; int* p1 = reinterpret_cast<int*>(&s1); // value of p1 is "pointer to s1.a" because // s1.a and s1 are pointer-interconvertible int* p2 = reinterpret_cast<int*>(&s2); // value of p2 is unchanged by reinterpret_cast // and is "pointer to s2". int* p3 = reinterpret_cast<int*>(&u); // value of p3 is "pointer to u.a": // u.a and u are pointer-interconvertible double* p4 = reinterpret_cast<double*>(p3); // value of p4 is "pointer to u.b": u.a and // u.b are pointer-interconvertible because // both are pointer-interconvertible with u int* p5 = reinterpret_cast<int*>(&arr); // value of p5 is unchanged by reinterpret_cast // and is "pointer to arr"
Das Durchführen eines Klassenmemberzugriffs, der einen nicht-statischen Datenmember oder eine nicht-statische Memberfunktion bezeichnet, auf ein glvalue, das tatsächlich kein Objekt des entsprechenden Typs bezeichnet – z. B. eines, das durch einen reinterpret_cast erhalten wurde – führt zu undefiniertem Verhalten.
struct S { int x; }; struct T { int x; int f(); }; struct S1 : S {}; // standard-layout struct ST : S, T {}; // not standard-layout S s = {}; auto p = reinterpret_cast<T*>(&s); // value of p is "pointer to s" auto i = p->x; // class member access expression is undefined behavior; // s is not a T object p->x = 1; // undefined behavior p->f(); // undefined behavior S1 s1 = {}; auto p1 = reinterpret_cast<S*>(&s1); // value of p1 is "pointer to the S subobject of s1" auto i = p1->x; // OK p1->x = 1; // OK ST st = {}; auto p2 = reinterpret_cast<S*>(&st); // value of p2 is "pointer to st" auto i = p2->x; // undefined behavior p2->x = 1; // undefined behavior
Viele Compiler geben in solchen Fällen "Strict Aliasing"-Warnungen aus, obwohl solche Konstrukte technisch gesehen etwas anderes verletzen als der Absatz, der üblicherweise als "Strict Aliasing Rule" bezeichnet wird.
Der Zweck von Strict Aliasing und verwandten Regeln ist die Ermöglichung einer typbasierten Alias-Analyse, die dezimiert würde, wenn ein Programm gültig eine Situation schaffen könnte, in der zwei Zeiger auf nicht verwandte Typen (z. B. ein int* und ein float*) gleichzeitig existieren und beide verwendet werden könnten, um denselben Speicher zu lesen oder zu schreiben (siehe diese E-Mail auf dem SG12-Reflektor). Daher führt jede Technik, die scheinbar in der Lage ist, eine solche Situation zu schaffen, notwendigerweise zu undefiniertem Verhalten.
Wenn die Bytes eines Objekts als Wert eines anderen Typs interpretiert werden müssen, können std::memcpy oder std::bit_cast(seit C++20) verwendet werden.
double d = 0.1; std::int64_t n; static_assert(sizeof n == sizeof d); // n = *reinterpret_cast<std::int64_t*>(&d); // Undefined behavior std::memcpy(&n, &d, sizeof d); // OK n = std::bit_cast<std::int64_t>(d); // also OK
|
Wenn die Implementierung std::intptr_t und/oder std::uintptr_t bereitstellt, dann ist eine Konvertierung von einem Zeiger auf einen Objekttyp oder cv void in diese Typen immer wohl-definiert. Dies ist jedoch für einen Funktionszeiger nicht garantiert. |
(seit C++11) |
In C greifen Aggregatkopien und -zuweisungen auf das Aggregatobjekt als Ganzes zu. Aber in C++ werden solche Aktionen immer über einen Memberfunktionsaufruf durchgeführt, der auf die einzelnen Unterobjekte zugreift, anstatt auf das gesamte Objekt (oder im Falle von Unions wird die Objektrepräsentation kopiert, d. h. über unsigned char).
[bearbeiten] Schlüsselwörter
[bearbeiten] Beispiel
Demonstriert einige Verwendungen von reinterpret_cast
#include <cassert> #include <cstdint> #include <iostream> int f() { return 42; } int main() { int i = 7; // pointer to integer and back std::uintptr_t v1 = reinterpret_cast<std::uintptr_t>(&i); // static_cast is an error std::cout << "The value of &i is " << std::showbase << std::hex << v1 << '\n'; int* p1 = reinterpret_cast<int*>(v1); assert(p1 == &i); // pointer to function to another and back void(*fp1)() = reinterpret_cast<void(*)()>(f); // fp1(); undefined behavior int(*fp2)() = reinterpret_cast<int(*)()>(fp1); std::cout << std::dec << fp2() << '\n'; // safe // type aliasing through pointer char* p2 = reinterpret_cast<char*>(&i); std::cout << (p2[0] == '\x7' ? "This system is little-endian\n" : "This system is big-endian\n"); // type aliasing through reference reinterpret_cast<unsigned int&>(i) = 42; std::cout << i << '\n'; [[maybe_unused]] const int &const_iref = i; // int &iref = reinterpret_cast<int&>( // const_iref); // compiler error - can't get rid of const // Must use const_cast instead: int &iref = const_cast<int&>(const_iref); }
Mögliche Ausgabe
The value of &i is 0x7fff352c3580 42 This system is little-endian 42
[bearbeiten] Fehlerberichte
Die folgenden Verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.
| DR | angewendet auf | Verhalten wie veröffentlicht | Korrigiertes Verhalten |
|---|---|---|---|
| CWG 195 | C++98 | Konvertierung zwischen Funktionszeigern und Objektzeigern nicht erlaubt |
Wurde bedingt unterstützt gemacht |
| CWG 658 | C++98 | das Ergebnis von Zeigerkonvertierungen war nicht spezifiziert (außer für Konvertierungen zurück zum ursprünglichen Typ) |
Spezifikation für Zeiger bereitgestellt, deren Zeigertypen erfüllen die Ausrichtungsanforderungen |
| CWG 799 | C++98 | es war unklar, welche Identitätskonvertierung mit reinterpret_cast durchgeführt werden kann |
wurde klargestellt |
| CWG 1268 | C++11 | reinterpret_cast konnte nur lvalues in Referenztypen konvertieren |
xvalues auch erlaubt |
| CWG 2780 | C++98 | reinterpret_cast konnte Funktions-lvalues nicht in andere Referenztypen konvertieren |
erlaubt |
| CWG 2939 | C++17 | reinterpret_cast konnte prvalues in rvalue-Referenztypen konvertieren |
nicht erlaubt |
[bearbeiten] Referenzen
- C++23 Standard (ISO/IEC 14882:2024)
- 7.6.1.10 Reinterpret cast [expr.reinterpret.cast]
- C++20 Standard (ISO/IEC 14882:2020)
- 7.6.1.9 Reinterpret cast [expr.reinterpret.cast]
- C++17 Standard (ISO/IEC 14882:2017)
- 8.2.10 Reinterpret cast [expr.reinterpret.cast]
- C++14 Standard (ISO/IEC 14882:2014)
- 5.2.10 Reinterpret cast [expr.reinterpret.cast]
- C++11 Standard (ISO/IEC 14882:2011)
- 5.2.10 Reinterpret cast [expr.reinterpret.cast]
- C++98 Standard (ISO/IEC 14882:1998)
- 5.2.10 Reinterpret cast [expr.reinterpret.cast]
- C++03-Standard (ISO/IEC 14882:2003)
- 5.2.10 Reinterpret cast [expr.reinterpret.cast]
[bearbeiten] Siehe auch
const_cast-Konvertierung
|
fügt const hinzu oder entfernt es |
static_cast-Konvertierung
|
führt grundlegende Konvertierungen durch |
dynamic_cast-Konvertierung
|
führt überprüfte polymorphe Konvertierungen durch |
| explizite Konvertierungen | permissive Konvertierungen zwischen Typen |
| Standardkonvertierungen | implizite Konvertierungen von einem Typ zu einem anderen |
| (C++20) |
interpretiert die Objekt-Repräsentation eines Typs als die eines anderen Typs neu (Funktion-Template) |