Ich verstehe, dass reinterpret_cast
das gefährlich ist, ich mache das nur, um es zu testen. Ich habe folgenden Code:
int x = 0;
double y = reinterpret_cast<double>(x);
Wenn ich versuche, das Programm zu kompilieren, wird eine Fehlermeldung angezeigt
ungültige Umwandlung von Typ 'float' in Typ 'double
Was ist los? Ich dachte, reinterpret_cast
es wäre die Schurkenbesetzung, mit der man Äpfel in U-Boote umwandeln könnte. Warum wird diese einfache Besetzung nicht kompiliert?
c++
casting
reinterpret-cast
Vlad der Impala
quelle
quelle
reinterpret_cast<double>(x)
Was haben Sie erwartet, dass dieser Ausdruck tut?"float
?float
Ihr Code-Snippet enthält keine .Antworten:
Vielleicht
reinterpret_cast
ist der Rouge-Operator, der Zeiger in Äpfel als Zeiger auf U-Boote "umwandeln" kann, eine bessere Denkweise .Indem Sie dem von der Besetzung zurückgegebenen Wert y zuweisen, wandeln Sie den Wert nicht wirklich um
x
, sondern konvertieren ihn. Das heißt,y
zeigt nicht aufx
und gibt vor, dass es auf einen Schwimmer zeigt. Die Konvertierung erstellt einen neuen Wert vom Typfloat
und weist ihm den Wert von zux
. Es gibt verschiedene Möglichkeiten, diese Konvertierung in C ++ durchzuführen, darunter:int main() { int x = 42; float f = static_cast<float>(x); float f2 = (float)x; float f3 = float(x); float f4 = x; return 0; }
Der einzige wirkliche Unterschied besteht darin, dass der letzte (eine implizite Konvertierung) eine Compilerdiagnose für höhere Warnstufen generiert. Aber sie alle tun funktional dasselbe - und in vielen Fällen sogar dasselbe wie im selben Maschinencode.
Wenn Sie wirklich so tun möchten,
x
als wäre dies ein Float, dann möchten Sie wirklich Folgendesx
tun:#include <iostream> using namespace std; int main() { int x = 42; float* pf = reinterpret_cast<float*>(&x); (*pf)++; cout << *pf; return 0; }
Sie können sehen, wie gefährlich das ist. Tatsächlich ist die Ausgabe, wenn ich dies auf meinem Computer ausführe
1
, definitiv nicht 42 + 1.quelle
(float)x
führt eine Konvertierung durch, keine Besetzung.In C ++
reinterpret_cast
können nur bestimmte Konvertierungen durchgeführt werden, die in der Sprachspezifikation explizit aufgeführt sind. Kurz gesagt,reinterpret_cast
kann nur Zeiger-zu-Zeiger-Konvertierungen und Referenz-zu-Referenz-Konvertierungen durchführen (plus Zeiger-zu-Ganzzahl- und Ganzzahl-zu-Zeiger-Konvertierungen). Dies steht im Einklang mit der Absicht, die im Namen der Besetzung zum Ausdruck kommt: Sie soll für die Neuinterpretation von Zeigern / Referenzen verwendet werden.Was Sie versuchen, ist keine Neuinterpretation. Wenn Sie eine
int
als neu interpretieren möchten, müssendouble
Sie sie in einen Referenztyp konvertierendouble y = reinterpret_cast<double&>(x);
obwohl die äquivalente zeigerbasierte Neuinterpretation wahrscheinlich expliziter ist
double y = *reinterpret_cast<double*>(&x); // same as above
Beachten Sie jedoch, dass
reinterpret_cast
der tatsächliche Versuch, die Daten über die resultierende Referenz / den resultierenden Zeiger zu lesen , zwar zu einer Konvertierung der Referenz- / Zeigertypen führt, jedoch zu einem undefinierten Verhalten führt.Und auf jeden Fall kann dies auf einer Plattform mit
int
unddouble
unterschiedlicher Größe nicht viel Sinn machen (da Sie bei größeren Plattformendouble
über den von gelesenen Speicher hinaus lesen werdenx
).Am Ende läuft alles auf das hinaus, was Sie erreichen wollten. Neuinterpretation des Gedächtnisses? Siehe oben. Eine Art von Bedeutung
int
für diedouble
Konvertierung? Wenn ja,reinterpret_cast
wird Ihnen hier nicht helfen.quelle
reinterpret_cast can only perform pointer-to-pointer conversions and reference-to-reference conversions (plus pointer-to-integer and integer-to-pointer conversions)
Dies drückte die Frage flach und konnte als Antwort akzeptiert werden.reinterpret_cast ist keine allgemeine Besetzung. Gemäß der C ++ 03-Spezifikation Abschnitt 5.2.10.1:
Und es ist nichts aufgeführt, was die Konvertierung zwischen Integral- und Gleitkommatypen beschreibt (oder zwischen Integraltypen, auch wenn dies illegal ist
reinterpret_cast<long>(int(3));
).quelle
Wenn Sie versuchen, die Bits von
int
a in die Darstellung von a umzuwandelndouble
, müssen Sie die Adresse und nicht den Wert umwandeln . Sie müssen auch sicherstellen, dass die Größen übereinstimmen:uint64_t x = 0x4045000000000000; double y = *reinterpret_cast<double *>(&x);
quelle
Der Compiler lehnt das, was Sie als Unsinn geschrieben haben, ab
int
unddouble
kann Objekte mit unterschiedlichen Größen sein. Sie könnten den gleichen Effekt auf diese Weise erzielen, obwohl dies sicherlich gefährlich ist:int x = 0; double y = *reinterpret_cast<double*>(&x);
Es ist sehr gefährlich , denn wenn
x
undy
sind diffrent Größen (sagen wir malint
vier Bytes unddouble
ist acht Byte) dann , wenn Sie die acht Byte Speicher dereferenzieren bei&x
ausfülleny
Sie vier Bytes zugreifenx
und vier Bytes von ... , was als nächstes kommt im Gedächtnis (möglicherweise der Anfangy
oder Müll oder etwas ganz anderes.)Wenn Sie eine Ganzzahl in ein Double konvertieren möchten, verwenden Sie a
static_cast
und es wird eine Konvertierung durchgeführt.Wenn Sie auf das Bitmuster von zugreifen möchten
x
, wandeln Sie es in einen geeigneten Zeigertyp (z. B.byte*
) um und greifen Sie auf zusizeof(int) / sizeof(byte)
:byte* p = reinterpret_cast<byte*>(&x); for (size_t i = 0; i < sizeof(int); i++) { // do something with p[i] }
quelle
Mit Cast neu interpretieren können Sie einen Speicherblock als einen anderen Typ interpretieren. Dies muss an Zeigern oder Referenzen durchgeführt werden :
int x = 1; float & f = reinterpret_cast<float&>(x); assert( static_cast<float>(x) != f ); // !!
Die andere Sache ist, dass es sich in der Tat um eine ziemlich gefährliche Besetzung handelt, nicht nur, weil seltsame Werte als Ergebnis herauskommen oder die obige Behauptung nicht fehlschlägt, sondern weil die Typen unterschiedlich groß sind und Sie von 'Quelle' zu 'neu' interpretieren 'Ziel'-Typen, jede Operation an der neu interpretierten Referenz / dem neu interpretierten Zeiger greift auf
sizeof(destination)
Bytes zu. Wenn diessizeof(destination)>sizeof(source)
dann über den tatsächlichen Variablenspeicher hinausgeht und möglicherweise Ihre Anwendung beendet oder andere Variablen als die Quelle oder das Ziel überschreibt:struct test { int x; int y; }; test t = { 10, 20 }; double & d = reinterpret_cast<double&>( t.x ); d = 1.0/3.0; assert( t.x != 10 ); // most probably at least. assert( t.y != 20 );
quelle
reinterpret_cast
wird am besten für Zeiger verwendet. So kann ein Zeiger auf ein Objekt in ein "U-Boot" verwandelt werden.Von msdn :
quelle
Das Umwandeln eines Int in ein Double erfordert keine Umwandlung. Der Compiler führt die Zuweisung implizit aus.
Der reinterpret_cast wird mit Zeigern und Referenzen verwendet, z. B. beim Casting von
int *
an adouble *
.quelle
Das ist interessant. Vielleicht wird eine implizite Konvertierung von int in float durchgeführt, bevor versucht wird, die Besetzung zu verdoppeln. int- und float-Typen haben in Byte normalerweise die gleiche Größe (abhängig von Ihrem System natürlich).
quelle
Die Neuinterpretation führte mich auf einen seltsamen Weg mit inkonsistenten Ergebnissen. Am Ende fand ich es viel besser, so etwas zu merken!
double source = 0.0; uint64_t dest; memcpy(&dest, &source, sizeof(dest));
quelle
Verwenden Sie eine Gewerkschaft. Dies ist die am wenigsten fehleranfällige Methode zur Speicherzuordnung zwischen einer Ganzzahl und einem Gleitkommatyp. Das erneute Interpretieren eines Zeigers führt zu Aliasing-Warnungen.
#include <stdio.h> #include <stdint.h> int main(int argc, char *argv[]) { union { uint32_t i; float f; } v; // avoid aliasing rules trouble v.i = 42; printf("int 42 is float %f\n", v.f); v.f = 42.0; printf("float 42 is int 0x%08x\n", v.i); }
quelle
i
32 Bit undf
64 Bit sind,i
entspricht dies den oberen oder unteren 32 Bits vonf
?