Namespaces
Variants

reinterpret_cast conversion

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

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).

1) Ein Ausdruck vom Typ Integer, Enumeration, Zeiger oder Zeiger-auf-Mitglied kann in seinen eigenen Typ konvertiert werden. Der resultierende Wert ist identisch mit dem Wert des expression .
2) Ein Zeiger kann in jeden integralen Typ konvertiert werden, der groß genug ist, um alle Werte seines Typs zu halten (z.B. in std::uintptr_t ).
3) Ein Wert jedes integralen oder Aufzählungstyps kann in einen Zeigertyp konvertiert werden. Ein Zeiger, der in eine Ganzzahl ausreichender Größe und zurück in denselben Zeigertyp konvertiert wird, garantiert den ursprünglichen Wert, andernfalls kann der resultierende Zeiger nicht sicher dereferenziert werden (die Rundum-Konvertierung in die entgegengesetzte Richtung ist nicht garantiert; derselbe Zeiger kann mehrere Ganzzahldarstellungen haben). Die Nullzeiger-Konstante NULL oder die Ganzzahl Null garantiert nicht den Nullzeigerwert des Zieltyps; 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)
5) Jeder Objektzeigertyp 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.
6) Ein lvalue (bis C++11) glvalue (seit C++11) -Ausdruck vom Typ 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.
7) Jeder Zeiger auf eine Funktion kann in einen Zeiger auf einen anderen Funktionstyp konvertiert werden. Das Ergebnis ist nicht spezifiziert, aber die Konvertierung eines solchen Zeigers zurück zu einem Zeiger auf den ursprünglichen Funktionstyp liefert den Zeiger auf die ursprüngliche Funktion. Der resultierende Zeiger kann nur sicher aufgerufen werden, wenn sein Funktionstyp aufrufkompatibel mit dem ursprünglichen Funktionstyp ist.
8) Auf einigen Implementierungen (insbesondere auf jedem POSIX-kompatiblen System, wie von 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.
9) Der Nullzeigerwert jedes Zeigertyps kann in jeden anderen Zeigertyp konvertiert werden, was den Nullzeigerwert dieses Typs ergibt. Beachten Sie, dass die Nullzeigerkonstante nullptr oder ein anderer Wert des Typs std::nullptr_t nicht mit reinterpret_cast in einen Zeiger konvertiert werden kann: Für diesen Zweck sollte eine implizite Konvertierung oder static_cast verwendet werden.
10) Ein Zeiger auf eine Memberfunktion kann in einen Zeiger auf eine andere Memberfunktion eines anderen Typs konvertiert werden. Die Rückkonvertierung in den ursprünglichen Typ liefert den ursprünglichen Wert, andernfalls kann der resultierende Zeiger nicht sicher verwendet werden.
11) Ein Zeiger auf ein Mitgliedsobjekt einer bestimmten Klasse 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) ;
  • ein xvalue, falls target-type eine Rvalue-Referenz auf Objekttyp ist;
(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_call ist derselbe Typ wie T_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

reinterpret_cast

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)