2010-11-05 8 views
6

Die reinterpret_cast, wie wir wissen, kann jeden Zeigertyp auf einen anderen Zeigertyp umwandeln. Die Frage, die ich zu diesem Cast-Operator fragen will, ist:Wenige Zweifel über Casting-Operatoren in C++

  1. Wie funktioniert reinterpret_cast Arbeit, was die Magie ist (die interne Implementierung), die reinterpret_cast erlaubt zu arbeiten?
  2. Wie gewährleistet man Sicherheit bei der Verwendung von reinterpret_cast? Soweit ich weiß, garantiert es nicht für sicheres Gießen, also welche Vorsichtsmaßnahme, um während der Verwendung zu nehmen reinterpret_cast?
  3. Was ist die praktische Verwendung dieses Betreibers. Ich habe es in meiner professionellen Programmiererfahrung nicht wirklich erlebt, in der ich nicht herumkommen konnte, ohne diesen Operator zu benutzen. Jedes praktische Beispiel abgesehen von gewöhnlichem int * char * wird sehr hilfreich und geschätzt sein.

Eine andere Frage zum Gießen Betreiber im Allgemeinen:
Casting-Operatoren (static_cast, dynamic_cast, const_cast, reinterpret_cast) all Operators genannt also ist zu meinem besten Verständnis ist es also richtige Aussage, dass machen casting operators cannot be overloaded unlike most other operators (Ich bin mir bewusst, dass nicht alle Betreiber überlastet sein können und ich weiß, was nicht sein kann (außer die QI frage, bitte unterlassen, mich darauf zu flammen). Ich hatte nur Zweifel, dass, da sie Betreiber sind, was der Standard sagt über diese?

+2

Was ist ein nicht standardmäßiger Zeiger? –

+0

Diese [link] (http://www.cplusplus.com/doc/tutorial/typecasting/) könnte es erklären. –

+0

@Konrad: Sorry ein Tippfehler, ich habe die Frage bearbeitet. –

Antwort

4
  1. Es gibt keine Magie. reinterpret_cast bedeutet in der Regel nur (zumindest versuchen) zu behandeln, was Sie an dieser Adresse finden, als wäre es der Typ, den ich angegeben habe. Der Standard definiert wenig genug darüber, was es macht, dass es könnte anders sein, aber es ist selten (wenn überhaupt) wirklich ist.
  2. In einigen Fällen können Sie sich vor einer diskriminierten Verbindung schützen. Wenn Sie zum Beispiel Netzwerkpakete lesen und genug lesen, um zu sehen, dass Sie ein TCP-Paket erhalten haben, können Sie (relativ) sicher eine reinterpret_cast von IPHdr bis TCPHdr (oder welche Namen Sie auch verwenden) machen). Der Compiler wird nicht (wieder, normalerweise) viel tun - jede Sicherheit liegt bei Ihnen zu implementieren und zu erzwingen.
  3. Ich habe Code wie ich in 2 beschrieben, verwendet, mit verschiedenen Arten von Netzwerkpaketen.

Für Ihre letzte Frage: Sie Casting für eine Klasse überlasten:

class XXX { 
public: 
    operator YYY() { return whatever; } 
}; 

Dies kann zwar für Konvertierungen im allgemeinen verwendet werden - ob durch einen static_cast getan, C-Casts oder sogar eine implizite Konvertierung C++ 0x ermöglicht es Ihnen, ein explicit Qualifikationsmerkmal hinzuzufügen, so dass es nicht für implizite Konvertierungen verwendet wird, aber es gibt immer noch keine Möglichkeit, zwischen einem statischen Cast und einem C-Style-Cast zu unterscheiden.

+2

Ich bekomme nicht den letzten Satz: '* Es gibt keine Möglichkeit, zwischen einem statischen Cast und einem C-Style-Cast * zu unterscheiden. Die Sache ist, dass C-artige Umwandlungen entweder 'static_cast' oder' reininterpret_cast' sein können (möglicherweise einschließlich 'const_cast' mit jedem von beiden). In allen Fällen, in denen ein 'static_cast' gültig ist, führt der C-Style-Cast einen' static_cast' durch, während es, wenn es nicht möglich ist, einen 'reinterpret_cast' ausführt. Wenn const-ness (oder volatile-ness) modifiziert wurde, wird es einen 'const_cast' in den Prozess einschließen. –

+0

@dribeas: Ich meinte nur, dass wenn Sie einen solchen Konvertierungsoperator definieren, dieser entweder über einen C-style-Fall oder einen static_cast im Client-Code aufgerufen werden kann und Sie beispielsweise keine Überladung für a bereitstellen können static_cast wird ausgeführt, und ein anderer für die Art, wie ein C-Style-Cast gemacht wird. –

+0

In der Antwort auf das finale Q heißt es "Operatorkonvertierung" und AFAIK das "explizite" Qualifikationsmerkmal ist sogar in C++ erlaubt. Mein finales Q bedeutete eigentlich, kann man überladen sagen wir dynamic_cast operator? –

2

reinterpret_cast im Allgemeinen können Sie einige ve tun ry schlechte dinge. Im Fall des Gießens eines Zeigers wird es erlauben, von einem Typ zum anderen zu gießen, was absolut keinen Grund hat anzunehmen, dass dies funktionieren sollte. Es ist, als würde man sagen: "Vertrau mir, ich möchte das wirklich tun". Was genau das ist, ist von einem System zum nächsten unberechenbar. Auf Ihrem System könnte es einfach die Bit-Muster kopieren, wo es wie auf einem anderen es auf eine (potentiell nützliche) Weise transformieren könnte.

z.B.

class Foo { 
    int a; 
}; 

class Bar { 
    int a; 
}; 

int main() { 

    Foo a; 

    // No inheritance relationship and not void* so must be reinterpret_cast 
    // if you really want to do it 
    Bar *b = reinterpret_cast<Bar*>(&a); 

    char buffer[sizeof(Bar)]; 

    Bar *c = reinterpret_cast<Bar*>(buffer); // alignment? 

} 

Lassen Sie sich ziemlich glücklich, dass Sie das tun, egal in welchem ​​Szenario. Manchmal, wenn Sie eine Manipulation auf niedriger Ebene vornehmen, könnte dies tatsächlich das sein, was Sie tun möchten. (Stellen Sie sich char * eines Puffer Casting zu einem benutzerdefinierten Typ)

Mögliche Fallstricke sind riesig, auch im einfachsten Fall wie ein Puffer, wo Ausrichtung möglicherweise ein Problem sein kann.

Mit dlsym() unter Linux ist es nützlich zu können void* zu einem Funktionszeiger, der sonst nicht definiert Verhalten in C++ ist. (Einige Systeme verwenden möglicherweise separate Adressräume oder Zeiger unterschiedlicher Größe!). Dies kann nur mit reinterpret_cast in C++ geschehen.

+0

"Undefined" ist technisch das falsche Wort. Die Arten von Konvertierungen, die "reinterpret_cast" ausführen kann, sind im Standard explizit definiert, und die Zuordnungen sind implementierungsdefiniert. –

+0

Ich dachte der void */function pointer war nicht definiert, aber reinterpret_cast würde akzeptieren. – Flexo

0

reinterpret_cast sagt dem Compiler "halt die Klappe, es ist eine Variable vom Typ T *" und es gibt keine Sicherheit es sei denn, es ist wirklich eine Variable des Typs T *. Bei den meisten Implementierungen wird einfach nichts getan - derselbe Wert in der Variablen wird an das Ziel übergeben.

Ihre Klasse kann Konvertierungsoperatoren für jeden Typ T * haben, und diese Konvertierungen werden entweder implizit unter bestimmten Bedingungen ausgeführt, oder Sie können sie explizit unter Verwendung von static_cast aufrufen.

+2

Auch wenn es wirklich eine Variable vom Typ T * ist, kann es sich falsch verhalten. Wenn Sie struct X: Y, Z {} haben und Sie ein X * mit Hilfe von reinterpret_cast in ein Z * umwandeln und dann diesen Zeiger verwenden, werden Sie wahrscheinlich schlechte Ergebnisse erhalten und Sie werden undefiniertes Verhalten bekommen. Obwohl X * kein Z * in einer sehr korrekten und standardmäßigen Ansicht ist, könnte es zu Missverständnissen führen, weil viele dies berücksichtigen, weil X ein Z ist, das X * ein Z * ist. –

-1

Der reinterpret_cast wie wir Zeiger jeden Nicht-Standard-Zeiger auf eine andere Nicht-Standard- werfen wissen kann.

Fast, aber nicht genau. Zum Beispiel können Sie nicht mit reinterpret_cast eine const int* in eine int* umwandeln. Dafür benötigen Sie const_cast.

Wie reinterpret_cast Arbeit, Was ist die Magie (die interne Implementierung), die reinterpret_cast erlaubt zu arbeiten?

Es gibt keine Magie. Letztendlich sind alle Daten nur Bytes. Das C++ - Typsystem ist lediglich eine Abstraktionsschicht, die dem Compiler sagt, wie jedes Byte zu "interpretieren" ist. A reinterpret_cast ähnelt einem einfachen C-Cast, indem es einfach "zur Hölle mit dem Typsystem" sagt: interpretiere diese Bytes als Typ X anstatt als Typ Y! "

Wie gewährleistet man Sicherheit bei der Verwendung von reinterpret_cast? Soweit ich weiß, es garantiert nicht für sicheres Casting, So welche Vorsichtsmaßnahme zu nehmen, während reinterpret_cast verwenden?

Nun, reinterpret_cast ist inhärent gefährlich. Du solltest es nur benutzen, wenn du wirklich weißt, was du tust. Versuchen Sie stattdessen static_cast zu verwenden. Das C++ - System schützt Sie davor, etwas zu Gefährliches zu tun, wenn Sie static_cast verwenden.

Was ist der praktische Nutzen dieses Bedieners. Ich habe nicht wirklich begegnet es in meiner beruflichen programing Erfahrung, wobei ich umgehen could'nt ohne dieses operator.Any praktischen Beispielen auseinander von üblichen int * * auf char wird sehr nützlich und geschätzt.

Es hat viele Anwendungen, aber in der Regel sind diese Anwendungen etwas "fortgeschritten". Wenn Sie beispielsweise einen Speicherpool verknüpfter Blöcke erstellen und Zeiger auf freie Blöcke auf den Blöcken selbst speichern, müssen Sie einen Block von reinterpret_cast von T* zu T** senden, um den Block als Zeiger auf den nächsten Block zu interpretieren , anstatt ein Block selbst.

+1

Sie sind der zweite Absatz ist falsch. 'reininterpret_cast' kann die Repräsentation ändern oder nicht (Standard 5.2.10/3), und das Mapping ist rein implementierungsdefiniert. Betrachte C Casting von 'int' zu' double' im Vergleich zum Casting von 'int *' zu 'int'. –

+2

Nein. Ein reinterpret_cast ist nicht wie ein C-Cast. –

+0

Der Hauptunterschied ist, dass reinterpret_cast keine Konstanz wegwerfen wird, was ich bemerkte. Abgesehen davon scheint die Reinterpret_cast-Umwandlung ähnlich zu einer einfachen C-Umwandlung in dem Sinne zu sein, dass man ein Bitmuster einfach als einen anderen Typ "uminterpretieren" kann, wenn man einen Zeigertyp auf einen anderen Zeigertyp umsetzt.Die Unterschiede sind subtil genug, dass die Verwendung des Wortes "ähnlich" hier in Ordnung ist. Auch wenn der C++ - Standard es Implementierungen erlaubt, das Bitmuster bei einem reinterpret_cast zu ändern, ist Casting zwischen zwei nicht verwandten Typen letztlich genauso gefährlich. –

-1

reinterpret_cast ist einem C-Style Cast sehr ähnlich. Es garantiert nichts; Es ist da, um Ihnen zu ermöglichen, das zu tun, was Sie brauchen, in der Hoffnung, dass Sie wissen, was Sie tun.

Wenn Sie nach Sicherheit suchen, verwenden Sie dynamic_cast, denn das ist es. Wenn die Umwandlung nicht sicher abgeschlossen werden kann, gibt dynamic_cast NULL oder nullptr (C++ 0x) zurück.

Casting mit den "casting operators" wie static_cast, dynamic_cast, etc .. kann nicht überlastet werden. Gerade Umwandlungen können, wie zum Beispiel:

class Degrees 
{ 
public: 
    operator double() { ... } 
}; 
+2

Ein reinterpret_cast ist nicht gleichbedeutend mit einem C-Style-Cast. Ein C-Style-Cast kann zu einem static_cast führen und kann tatsächlich einige sehr seltene Dinge tun, die mit einem neuen Cast nicht möglich sind. –

1
  1. reinterpret_cast funktioniert nur auf Zeiger.Die Art und Weise, wie es funktioniert, ist, dass es den Wert des Zeigers alleine lässt und die angenommene Typinformation darüber ändert. Es heißt: "Ich weiß, dass diese Typen nicht gleichwertig sind, aber ich möchte, dass Sie so tun, als wäre dies jetzt ein Zeiger auf T2." Natürlich kann dies zu einer Reihe von Problemen führen, wenn Sie den T2-Zeiger verwenden und nicht auf T2 zeigen.

  2. Es gibt sehr wenige Garantien über reinterpret_cast, weshalb es so vermieden werden soll. Du darfst wirklich nur von T1 nach T2 und dann zurück nach T1 umwandeln und weißt, dass das Endergebnis mit einigen Annahmen übereinstimmt, mit dem was du angefangen hast.

  3. Die einzige, die ich denken kann, ist ein char * zu einem unsigned char * zu werfen. Ich weiß, dass die zugrunde liegende Darstellung in meiner Implementierung die gleiche ist, daher weiß ich, dass die Besetzung sicher ist. Ich kann jedoch keine statische Umwandlung verwenden, da es sich um einen Zeiger auf einen Puffer handelt. In Wirklichkeit werden Sie reinterpret_cast in der realen Welt kaum legitim verwenden.

Ja, sie sind Betreiber. AFAIK kannst du nicht überschreiben.

+2

Hallo Noah. Lange nicht gesehen :-). Nit re (1): reinterpret_cast funktioniert auch gut auf Referenzen. Nit re (2): Es gibt auch eine Garantie für die Neuinterpretation von/zum ersten Member einer POD-Struktur. Re (3), kein Nit: Siehe meine Antwort (ein Beispiel ist Microsofts "QueryInterface"). Prost, –

+1

Ja, wenn Sie die C- und/oder C++ - Bibliotheken von MS verwenden, werden Sie wahrscheinlich reinterpret_cast sehr oft verwenden müssen, weil Sie vage statt void * verwenden. Die meisten anderen C-Bibliotheken, die ich benutzt habe, benutzten void *. Ich kenne nicht die Geschichte oder die Gründe, warum MS lange statt gewählt, aber Sie können static_cast zu/von void * (obwohl es nicht wirklich viel sicherer ist). Ich denke, ich wusste nicht, dass es auf Referenzen funktioniert ... nie getan. Und ja, ich kenne nicht alle Regeln, außer ich muss. –

2

Zunächst ist es unklar, was Sie mit "Nicht-Standard-Zeiger" meinen. Ich denke, deine Prämisse ist fehlerhaft. Glücklicherweise scheint es die Fragen nicht zu beeinflussen.

"Wie funktioniert [es]?" Nun, die Absicht, wie Sie aus dem Namen erraten können, besteht darin, nur die Interpretation eines Bitpatterns zu ändern, möglicherweise entsprechend zu erweitern oder kurzzuschließen. Dies ist eine Art Typänderung, bei der das Bitmuster unverändert bleibt, aber die Interpretation und damit der konzeptionelle Wert geändert wird. Und es steht im Gegensatz zu einer Art von Typänderung, bei der der konzeptionelle Wert beibehalten wird (z. B. int konvertiert zu double), während das Bitmuster wie erforderlich geändert wird, um den konzeptionellen Wert beizubehalten. Aber die meisten Fälle von reinterpret_cast haben Auswirkungen auf die Implementierung, also kann der Compiler in diesen Fällen tun, was er will - und nicht unbedingt das Bitmuster beibehalten - solange er dokumentiert ist.

"Wie zur Gewährleistung der Sicherheit" Das ist zu wissen, was Ihr Compiler tut, und über vermeidenreinterpret_cast. :-)

"Was ist die praktische Verwendung". Meistens handelt es sich um die Wiederherstellung von Typinformationen, die in C-orientiertem Code verloren gegangen sind, wobei void* Zeiger verwendet werden, um Polymorphismus zu emulieren.

Beifall & hth.,

+1

Conversions von 'void *' erfordern nicht 'reininterpret_cast', sondern' static_cast' (was in diesem speziellen Fall genauso schlimm ist wie ein 'reininterpret_cast', aber * anders * nicht weniger) –

+0

Außer dass Sie static_cast to/aus void *, nein? Das Problem mit der MS-Schnittstelle ist, dass sie Ganzzahlen anstelle von void * verwenden. Ist das static_cast zu/von void * auch nicht 'etwas' sicherer, da es garantiert ist, den Anfang des Objekts zu greifen, anstatt nur den Typ des Zeigers zu wechseln? Ich denke, dass es für beide Methoden Fälle geben kann, da das Umsetzen von einem void * in eine Unterklasse in einem MI-Derivat schlecht mit static_cast verlaufen würde. Meistens erinnere ich mich daran, dass ich static_cast benutze. –

+0

@David: So weit wie es geht. Ich dachte hauptsächlich an Fälle wie in Microsoft [QueryInterface] (http://msdn.microsoft.com/en-us/library/ms682521%28VS.85%29.aspx). Die direkte Umwandlung von 'void **' nach 'T **' erfordert 'reininterpret_cast'. Prost, –

0

Ich habe reinterpret_cast viel in Windows-Programmierung verwendet. Die Nachrichtenbehandlung verwendet WPARAM- und LPARAM-Parameter, die auf die richtigen Typen umgesetzt werden müssen.

1

Eine "praktische" Verwendung von reinterpret_cast.

Ich habe eine Klasse, in der die Mitglieder nicht gelesen werden sollen. Beispiel unter

Diese Klasse wird an tausend Orten in einer Anwendung problemlos verwendet.

Nun, aus irgendeinem Grund möchte ich die Mitglieder in einem bestimmten Teil sehen. Ich möchte jedoch nicht die vorhandene Klasse berühren. So brechen Sie die Regeln wie folgt.

Erstellen Sie eine andere Klasse mit dem gleichen Bitmuster und der öffentlichen Sichtbarkeit. Hier enthält die ursprüngliche Klasse ein int und ein double.

class ExposeAnotherClass 
{ 
public: 
    int a_exposed; 
    double m_exposed; 
}; 

Wenn Sie möchten die Mitglieder der ClassWithHiddenVariables sehen Objekt, verwenden reinterpret_cast zu ExposeAnotherClass zu werfen. Beispiel folgt

ClassWithHiddenVariables obj; 
obj.SetVariables(10, 20.02);  
ExposeAnotherClass *ptrExposedClass; 
ptrExposedClass = reinterpret_cast<ExposeAnotherClass*>(&obj); 
cout<<ptrExposedClass->a_exposed<<"\n"<<ptrExposedClass->m_exposed; 

Ich glaube nicht, dass diese Situation jemals in der realen Welt auftritt. Aber das ist nur eine Erklärung von reinterpret_cast, die Objekte als Bitmuster betrachtet.

+0

Schöne Workaround :) –

+0

@Als, danke. Wenn wir mehr darüber nachdenken, können wir sehen, dass reinterpret_cast in C++ für "Vollständigkeit" vorhanden sein sollte. – Jimmy