reinterpret_cast
conversion
Konvertiert zwischen Typen durch Neuinterpretation des zugrundeliegenden Bitmusters.
Inhaltsverzeichnis |
Syntax
reinterpret_cast<
Zieltyp
>(
Ausdruck
)
|
|||||||||
Gibt einen Wert vom Typ target-type zurück.
Erklärung
Im Gegensatz zu static_cast , aber ähnlich wie const_cast , generiert der reinterpret_cast -Ausdruck keine CPU-Befehle (außer bei der Konvertierung zwischen Ganzzahlen und Zeigern oder zwischen Zeigern auf obskuren Architekturen, bei denen die Zeigerdarstellung vom Typ abhängt). Es handelt sich primär um eine Compile-Time-Direktive, die den Compiler anweist, expression so zu behandeln, als hätte es den Typ target-type .
Nur die folgenden Konvertierungen können mit reinterpret_cast durchgeführt werden, außer wenn solche Konvertierungen Constness entfernen würden (oder Volatilität).
static_cast
oder
implizite Konvertierung
sollte 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 es sich um
(
void
*
)
0
handeln würde, 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
*
>
(
expression
)
)
(was impliziert, dass wenn die Ausrichtungsanforderung von
T2
nicht strenger ist als die von
T1
, sich der Zeigerwert nicht ändert und die Konvertierung des resultierenden Zeigers zurück zu seinem ursprünglichen Typ den ursprünglichen Wert liefert). In jedem Fall darf der resultierende Zeiger nur sicher dereferenziert werden, wenn der dereferenzierte Wert
typzugreifbar
ist.
T1
kann in eine Referenz auf einen anderen Typ
T2
konvertiert werden. Das Ergebnis entspricht
*
reinterpret_cast
<
T2
*
>
(
p
)
, wobei
p
ein Zeiger vom Typ "Zeiger auf
T1
" auf das Objekt oder die Funktion ist, die durch
expression
bezeichnet wird. Es wird kein Temporärobjekt
materialisiert oder
(seit C++17)
erstellt, keine Kopie erstellt, keine Konstruktoren oder Konvertierungsfunktionen aufgerufen. Auf die resultierende Referenz kann nur sicher zugegriffen werden, wenn sie
typzugreifbar
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, liefert die Rückkonvertierung 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 Mitgliedsobjekt einer anderen Klasse
T2
konvertiert werden. Wenn die Ausrichtung von
T2
nicht strenger ist als die von
T1
, ergibt die Rückkonvertierung 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, falls target-type ein lvalue-Referenztyp ist oder ein rvalue-Referenztyp auf Funktionstyp (seit C++11) ;
|
(since C++11) |
- ein prvalue andernfalls.
Typaliasierung
Typzugänglichkeit
Wenn ein Typ
T_ref
ähnlich
zu einem der folgenden Typen ist, ist ein Objekt vom
dynamischen Typ
T_obj
typzugänglich
durch einen
Lvalue
(bis C++11)
Glvalue
(seit C++11)
vom Typ
T_ref
:
- char , unsigned char oder std::byte (seit C++17) : dies ermöglicht die Untersuchung der Objektdarstellung eines beliebigen Objekts als Byte-Array.
-
T_obj -
der entsprechende vorzeichenbehaftete oder vorzeichenlose Typ zu
T_obj
Wenn ein Programm versucht, den gespeicherten Wert eines Objekts durch einen lvalue (bis C++11) glvalue (seit C++11) zu lesen oder zu modifizieren, durch den es nicht typzugreifbar ist, ist das Verhalten undefiniert.
Diese Regel ermöglicht typbasierte Alias-Analyse, bei der ein Compiler annimmt, dass der über einen Glvalue eines Typs gelesene Wert nicht durch einen Schreibzugriff auf einen Glvalue eines anderen Typs verändert wird (vorbehaltlich der oben genannten Ausnahmen).
Beachten Sie, dass viele C++-Compiler diese Regel als nicht standardkonforme Spracherweiterung lockern, um Zugriffe mit falschem Typ über das inaktive Mitglied einer union zu erlauben (solche Zugriffe sind in C nicht undefiniert).
Aufrufkompatibilität
Wenn eine der folgenden Bedingungen erfüllt ist, ist ein Typ
T_call
call-compatible
mit einem Funktionstyp
T_func
:
-
T_callist derselbe Typ wieT_func.
|
(seit C++17) |
Wenn eine Funktion durch einen Ausdruck aufgerufen wird, dessen Funktionstyp nicht aufrufkompatibel mit dem Typ der Definition der aufgerufenen Funktion ist, ist das Verhalten undefiniert.
Hinweise
Vorausgesetzt, dass die Ausrichtungsanforderungen erfüllt sind, ändert ein reinterpret_cast den Wert eines Zeigers nicht, außer in einigen wenigen eingeschränkten Fällen, die zeigerinterkonvertierbare Objekte betreffen:
struct S1 { int a; } s1; struct S2 { int a; private: int b; } s2; // nicht standard-layout union U { int a; double b; } u = {0}; int arr[2]; int* p1 = reinterpret_cast<int*>(&s1); // Wert von p1 ist "Zeiger auf s1.a", weil // s1.a und s1 zeiger-interkonvertierbar sind int* p2 = reinterpret_cast<int*>(&s2); // Wert von p2 wird durch reinterpret_cast nicht geändert // und ist "Zeiger auf s2". int* p3 = reinterpret_cast<int*>(&u); // Wert von p3 ist "Zeiger auf u.a": // u.a und u sind zeiger-interkonvertierbar double* p4 = reinterpret_cast<double*>(p3); // Wert von p4 ist "Zeiger auf u.b": u.a und // u.b sind zeiger-interkonvertierbar, weil // beide mit u zeiger-interkonvertierbar sind int* p5 = reinterpret_cast<int*>(&arr); // Wert von p5 wird durch reinterpret_cast nicht geändert // und ist "Zeiger auf arr"
Das Ausführen eines Klassenmitgliederzugriffs, der auf einen nicht-statischen Datenelement oder eine nicht-statische Memberfunktion verweist, auf einen Glvalue, der tatsächlich kein Objekt des entsprechenden Typs bezeichnet - wie 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 {}; // Kein Standard-Layout S s = {}; auto p = reinterpret_cast<T*>(&s); // Wert von p ist "Zeiger auf s" auto i = p->x; // Klassenmember-Zugriffsausdruck ist undefiniertes Verhalten; // s ist kein T-Objekt p->x = 1; // Undefiniertes Verhalten p->f(); // Undefiniertes Verhalten S1 s1 = {}; auto p1 = reinterpret_cast<S*>(&s1); // Wert von p1 ist "Zeiger auf das S-Subobjekt von s1" auto i = p1->x; // OK p1->x = 1; // OK ST st = {}; auto p2 = reinterpret_cast<S*>(&st); // Wert von p2 ist "Zeiger auf st" auto i = p2->x; // Undefiniertes Verhalten p2->x = 1; // Undefiniertes Verhalten
Viele Compiler geben in solchen Fällen "strict aliasing"-Warnungen aus, obwohl solche Konstrukte technisch gesehen mit etwas anderem als dem Abschnitt in Konflikt geraten, der allgemein als "strict aliasing rule" bekannt ist.
Der Zweck von striktem Aliasing und verwandten Regeln ist es, typbasierte Alias-Analyse zu ermöglichen, die zunichtegemacht würde, wenn ein Programm gültigerweise eine Situation erzeugen könnte, in der zwei Zeiger auf unabhängige Typen (z.B. ein int * und ein float * ) gleichzeitig existieren und beide verwendet werden könnten, um denselben Speicher zu laden oder zu speichern (siehe diese E-Mail im SG12-Reflector ). Daher ruft jede Technik, die scheinbar in der Lage ist, eine solche Situation zu erzeugen, notwendigerweise undefiniertes Verhalten hervor.
Wenn es notwendig ist, die Bytes eines Objekts als Wert eines anderen Typs zu interpretieren, std::memcpy oder std::bit_cast (seit C++20) können verwendet werden:
double d = 0.1; std::int64_t n; static_assert(sizeof n == sizeof d); // n = *reinterpret_cast<std::int64_t*>(&d); // Undefiniertes Verhalten std::memcpy(&n, &d, sizeof d); // OK n = std::bit_cast<std::int64_t>(d); // ebenfalls OK
|
Falls die Implementierung std::intptr_t und/oder std::uintptr_t bereitstellt, dann ist eine Konvertierung von einem Zeiger auf einen Objekttyp oder cv void zu diesen Typen immer wohldefiniert. Dies ist jedoch für einen Funktionszeiger nicht garantiert. |
(since C++11) |
In C erfolgen Aggregat-Kopie und -Zuweisung Zugriff auf das Aggregat-Objekt als Ganzes. Aber in C++ werden solche Aktionen immer durch einen Member-Funktionsaufruf durchgeführt, der auf die einzelnen Subobjekte zugreift, anstatt auf das gesamte Objekt (oder, im Fall von Unions, kopiert die Objektrepräsentation, d.h. via unsigned char ).
Schlüsselwörter
Beispiel
Demonstriert einige Anwendungen von reinterpret_cast :
#include <cassert> #include <cstdint> #include <iostream> int f() { return 42; } int main() { int i = 7; // Zeiger zu Ganzzahl und zurück std::uintptr_t v1 = reinterpret_cast<std::uintptr_t>(&i); // static_cast ist ein Fehler std::cout << "The value of &i is " << std::showbase << std::hex << v1 << '\n'; int* p1 = reinterpret_cast<int*>(v1); assert(p1 == &i); // Funktionszeiger zu anderem und zurück void(*fp1)() = reinterpret_cast<void(*)()>(f); // fp1(); undefiniertes Verhalten int(*fp2)() = reinterpret_cast<int(*)()>(fp1); std::cout << std::dec << fp2() << '\n'; // sicher // Typ-Aliasing durch Zeiger char* p2 = reinterpret_cast<char*>(&i); std::cout << (p2[0] == '\x7' ? "This system is little-endian\n" : "This system is big-endian\n"); // Typ-Aliasing durch Referenz 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-Fehler - const kann nicht entfernt werden // Muss const_cast verwenden: int &iref = const_cast<int&>(const_iref); }
Mögliche Ausgabe:
The value of &i is 0x7fff352c3580 42 This system is little-endian 42
Fehlerberichte
Die folgenden verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.
| DR | Angewendet auf | Verhalten wie veröffentlicht | Korrektes Verhalten |
|---|---|---|---|
| CWG 195 | C++98 |
Konvertierung zwischen Funktionszeigern
und Objektzeigern nicht erlaubt |
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 referenzierte Typen die Ausrichtungsanforderungen erfüllen |
| CWG 799 | C++98 |
es war unklar, welche Identitätskonvertierung
durch reinterpret_cast durchgeführt werden kann |
klargestellt |
| CWG 1268 | C++11 |
reinterpret_cast
konnte nur
L-Werte zu Referenztypen konvertieren |
X-Werte ebenfalls erlaubt |
| CWG 2780 | C++98 |
reinterpret_cast
konnte
Funktions-L-Werte nicht zu anderen Referenztypen konvertieren |
erlaubt |
| CWG 2939 | C++17 |
reinterpret_cast
konnte
PR-Werte zu R-Wert-Referenztypen konvertieren |
nicht erlaubt |
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]
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 geprüfte polymorphe Konvertierungen durch |
| explizite Casts | erlaubende Konvertierungen zwischen Typen |
| Standardkonvertierungen | implizite Konvertierungen von einem Typ zu einem anderen |
|
(C++20)
|
interpretiert die Objektdarstellung eines Typs als die eines anderen um
(Funktionstemplate) |