Waarom compileert deze reinterpret_cast niet?

Ik begrijp dat reinterpret_castgevaarlijk 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_castde 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_castalleen een specifieke set conversies uitvoeren, expliciet vermeld in de taalspecificatie. Kortom, reinterpret_castkan 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 intopnieuw 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_castde 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 inten doublevan verschillende grootte (aangezien in het geval van grotere doublelees 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 intnaar doubleconversie? Als dat zo is, zal reinterpret_castje hier niet helpen.


Antwoord 2, autoriteit 92%

Misschien is een betere manier van denken over reinterpret_castde 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, yverwijst niet naar xen doet alsof het naar een float wijst. Conversie construeert een nieuwe waarde van het type floaten 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 xeen float is, dan wil je echt xcasten 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 intprobeert 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 inten doubleobjecten 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 xen yverschillende grootten zijn (laten we zeggen dat intvier bytes is en doubleis acht bytes) en wanneer u de referentie van de acht bytes geheugen bij &xom yin te vullen, krijgt u toegang tot vier bytes van xen 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_casten 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_castwordt 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 *.

Other episodes