Ik begrijp dat reinterpret_cast
gevaarlijk is, ik doe dit alleen om het te testen. Ik heb de volgende code:
int x = 0;
double y = reinterpret_cast<double>(x);
Als ik het programma probeer te compileren, krijg ik de foutmelding
ongeldige cast van type ‘float’ naar type ‘double
Wat is er aan de hand? Ik dacht dat reinterpret_cast
de malafide cast was die je kon gebruiken om appels om te zetten in onderzeeërs, waarom zou deze eenvoudige cast niet compileren?
Antwoord 1, autoriteit 100%
In C++ kan reinterpret_cast
alleen een specifieke set conversies uitvoeren, expliciet vermeld in de taalspecificatie. Kortom, reinterpret_cast
kan alleen pointer-naar-pointer-conversies en referentie-naar-referentie-conversies uitvoeren (plus pointer-naar-integer- en integer-naar-pointer-conversies). Dit komt overeen met de bedoeling die in de naam van de cast wordt uitgedrukt: het is bedoeld om te worden gebruikt voor herinterpretatie van aanwijzer/referentie.
Wat je probeert te doen is geen herinterpretatie. Als u een int
opnieuw wilt interpreteren als een double
, moet u deze converteren naar een referentietype
double y = reinterpret_cast<double&>(x);
hoewel de equivalente herinterpretatie op basis van pointers waarschijnlijk explicieter is
double y = *reinterpret_cast<double*>(&x); // same as above
Houd er echter rekening mee dat terwijl reinterpret_cast
de referentie-/aanwijzertypes kan converteren, de feitelijke poging om de gegevens te lezen via de resulterende referentie/aanwijzer ongedefinieerd gedrag produceert.
En in ieder geval heeft dit natuurlijk weinig zin op een platform met int
en double
van verschillende grootte (aangezien in het geval van grotere double
lees je verder dan het geheugen dat wordt ingenomen door x
).
Dus uiteindelijk komt het allemaal neer op wat je probeerde te bereiken. Herinterpretatie van het geheugen? Zie hierboven. Een soort van meer betekenisvolle int
naar double
conversie? Als dat zo is, zal reinterpret_cast
je hier niet helpen.
Antwoord 2, autoriteit 92%
Misschien is een betere manier van denken over reinterpret_cast
de rouge-operator die pointersnaar appels kan “converteren” als pointersnaar onderzeeërs.
Door y toe te wijzen aan de waarde die door de cast wordt geretourneerd, cast je niet echt de waarde x
, maar converteer je deze. Dat wil zeggen, y
verwijst niet naar x
en doet alsof het naar een float wijst. Conversie construeert een nieuwe waarde van het type float
en wijst deze de waarde toe van x
. Er zijn verschillende manieren om deze conversie in C++ uit te voeren, waaronder:
int main()
{
int x = 42;
float f = static_cast<float>(x);
float f2 = (float)x;
float f3 = float(x);
float f4 = x;
return 0;
}
Het enige echte verschil dat de laatste is (een impliciete conversie), genereert een compilerdiagnose op hogere waarschuwingsniveaus. Maar functioneel doen ze allemaal hetzelfde — en in veel gevallen eigenlijkhetzelfde, zoals in dezelfde machinecode.
Als je nu echt wilt doen alsof x
een float is, dan wil je echt x
casten door dit te doen:
#include <iostream>
using namespace std;
int main()
{
int x = 42;
float* pf = reinterpret_cast<float*>(&x);
(*pf)++;
cout << *pf;
return 0;
}
Je kunt zien hoe gevaarlijk dit is. In feite is de output wanneer ik dit op mijn machine uitvoer 1
, wat beslist geen 42+1 is.
Antwoord 3, autoriteit 24%
Als je de bits van je int
probeert te converteren naar de representatie van een double
, moet je het adresniet casten de waarde. Je moet er ook voor zorgen dat de maten overeenkomen:
uint64_t x = 0x4045000000000000;
double y = *reinterpret_cast<double *>(&x);
Antwoord 4, autoriteit 24%
reinterpret_cast is geen algemene cast. Volgens de C++03 spec sectie 5.2.10.1:
Conversies die expliciet kunnen worden uitgevoerd met reinterpret_cast staan hieronder vermeld. Er kan geen andere conversie expliciet worden uitgevoerd met reinterpret_cast.
En er wordt niets vermeld dat het converteren tussen integrale en drijvende-kommatypen beschrijft (of tussen integrale typen, zelfs dit is illegaal reinterpret_cast<long>(int(3));
)
Antwoord 5, autoriteit 12%
De compiler verwerpt wat je schreef als onzin omdat int
en double
objecten met verschillende afmetingen kunnen zijn. Je zou op deze manier hetzelfde effect kunnen bereiken, hoewel het zeker gevaarlijk is:
int x = 0;
double y = *reinterpret_cast<double*>(&x);
Dit is potentieel gevaarlijk omdat als x
en y
verschillende grootten zijn (laten we zeggen dat int
vier bytes is en double
is acht bytes) en wanneer u de referentie van de acht bytes geheugen bij &x
om y
in te vullen, krijgt u toegang tot vier bytes van x
en vier bytes van … wat er daarna in het geheugen komt (mogelijk het begin van y
, of afval, of iets heel anders.)
Als je een geheel getal naar een double wilt converteren, gebruik dan een static_cast
en het zal de conversie uitvoeren.
Als u toegang wilt tot het bitpatroon van x
, cast naar een handig aanwijzertype (bijvoorbeeld byte*
) en toegang tot maximaal sizeof(int) / sizeof(byte)
:
byte* p = reinterpret_cast<byte*>(&x);
for (size_t i = 0; i < sizeof(int); i++) {
// do something with p[i]
}
Antwoord 6, autoriteit 8%
Met cast herinterpreteren kun je een geheugenblok herinterpreteren als een ander type. Dit moet worden uitgevoerd op pointers of referenties:
int x = 1;
float & f = reinterpret_cast<float&>(x);
assert( static_cast<float>(x) != f ); // !!
Het andere is dat het in feite een behoorlijk gevaarlijke cast is, niet alleen vanwege vreemde waarden die als resultaten uitkomen, of de bewering hierboven niet faalt, maar omdat als de typen van verschillende grootte zijn, en je herinterpreteert van ‘ source’ naar ‘destination’ typen, zal elke bewerking op de geherinterpreteerde referentie/pointer toegang krijgen tot sizeof(destination)
bytes. Als sizeof(destination)>sizeof(source)
dan verder gaat dan het eigenlijke variabele geheugen, waardoor uw toepassing mogelijk wordt vernietigd of andere variabelen dan de bron of het doel worden overschreven:
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 );
Antwoord 7, autoriteit 4%
De herinterpretatie-aanpak leidde me op een vreemd pad met inconsistente resultaten. Uiteindelijk vond ik het veel beter om zo te memcpy!
double source = 0.0;
uint64_t dest;
memcpy(&dest, &source, sizeof dest);
Antwoord 8
reinterpret_cast
wordt het best gebruikt voor verwijzingen. Dus een aanwijzer naar één object kan worden omgezet in een “onderzeeër”.
Van msdn:
De operator reinterpret_cast kan zijn
gebruikt voor conversies zoals char* naar
int*, of One_class* naar
Niet-gerelateerde_class *, die inherent zijn
onveilig.het resultaat van een herinterpret_cast
kan niet veilig voor alles worden gebruikt
anders dan terug te werpen naar zijn
origineel type. Andere toepassingen zijn, op
Beste, Nonortable.
9
het gieten van een int naar een dubbele vereiste geen cast. De compiler voert de opdracht impliciet uit.
De reinterpret_cast wordt gebruikt met aanwijzingen en referenties, b.v., het gieten van een int *
naar een double *
.