2017-12-28 15 views
2

int Ich mag einen Zeiger pc werfen, die pi zu einem Punkt verkohlen Punkte, dieWie ein Zeiger werfen auf einen Zeiger auf char

char *pc; 
int *pi; 
pi = (int*)pc         // compiler complaint about old-style cast 
pi = static_cast<int *>(static_cast<void *>(pc)) // no complaint any more but too complex 

int Punkte gibt es keine einfacheren Möglichkeiten, diese Besetzung zu tun und den Compiler zum Schweigen bringen?

+1

Zunächst, warum versuchen Sie dies zu tun? Es ist kompliziert/eine Warnung, weil es Code riecht. Zweitens, warum bist du mit der zweiten Version unzufrieden? Es funktioniert, oder? –

+1

'(int *) pc' ist kurz, aber es [verbirgt eine heftige Konvertierung] (http://en.cppreference.com/w/cpp/language/explicit_cast). Dein Compiler warnt dich wahrscheinlich, damit du nicht überrascht wirst. Wenn Sie die Konvertierungen explizit buchstabieren, wird davon ausgegangen, dass Sie genau wissen, was Sie tun. – StoryTeller

+4

Was versuchst du eigentlich? Der Zugriff auf einen solchen Zeiger ist (normalerweise) ein undefiniertes Verhalten. Normalerweise müssen Sie einen Weg auslegen, das 'int *' immer zu einem 'char *' zu machen, nicht umgekehrt. – Galik

Antwort

1

ich die Rückseite setzen wollen und her unter @Bathsheba's post ruhen. Also hier ist eine Antwort über die feineren Details von dem, was Sie tun.


@Sean already suggested Sie reinterpret_cast Ihre Zeiger statt. Und das ist gleichbedeutend mit deiner zweiten Verkettung. Es sagt so viel in [expr.reinterpret.cast]/7:

Ein Objektzeiger kann explizit auf einen Objektzeiger von eine andere Art umgewandelt werden. Wenn ein Prvalue v des Objekt-Zeigertyps in den Objektzeiger Typ "Zeiger auf CV T" konvertiert wird, ist das Ergebnis static_­cast<cv T*>(static_­cast<cv void*>(v)). [Anmerkung: Konvertieren eines prvalue des Typs „Zeiger auf T1“ auf den Typ „Zeiger auf T2“ (wobei T1 und T2 Objekttypen sind und wobei die Ausrichtungsanforderungen der T2 sind nicht strenger als die von T1) und zurück zu Der ursprüngliche Typ liefert den ursprünglichen Zeigerwert . - Endnote]

Nun untersuchen wir jeden Schritt der zweistufigen Umwandlung. Zuerst haben wir eine static_cast<void*>. Nach [conv.ptr]/2 (Hervorhebung von mir):

A prvalue des Typs „Zeiger auf cv T“, wobei T ein Objekttyp ist, kann auf eine prvalue des Typs „Zeiger auf cv void“ umgewandelt werden. Der Zeigerwert ist durch diese Konvertierung unverändert.

Die erste Konvertierung ändert nichts an der Adresse.Und dann heißt es auch in [basic.compound]/5:

Ein Zeiger auf cv-qualifiziert oder cv-unqualifizierten void kann verwendet werden, um Objekte unbekannter Art zu zeigen. Ein solcher Zeiger soll einen Objektzeiger halten können. Ein Objekt vom Typ cv void* muss dieselben Anforderungen an die Darstellung und Ausrichtung haben wie , cv char*.

So ein char* speichern kann jede Adresse ein void* speichern. Nun heißt das nicht, dass die Konvertierung von void* zu char* wertschonend ist, nur dass sie die gleichen Werte repräsentieren können. Unter der Annahme eines sehr eingeschränkten Anwendungsfalls ist dies eine Garantie. Aber es gibt mehr zu [expr.static.cast]/13:

A prvalue vom Typ „Zeiger auf cv1 Leere“ kann vom Typ „Zeiger auf cv2 T“ zu einem prvalue umgewandelt werden, wobei T ein Objekttyp und cv2 das ist gleiche cv-Qualifikation als oder höhere cv-Qualifikation als, cv1. Wenn der ursprüngliche Zeigerwert die Adresse A eines Bytes in Speicher darstellt und A die Ausrichtungsanforderung von T nicht erfüllt, dann ist der resultierende Zeigerwert nicht spezifiziert. Andernfalls, wenn der ursprüngliche Zeigerwert auf ein Objekt a zeigt und es ein Objekt b vom Typ T (Ignorieren von cv-qualification) gibt, das mit a, Zeiger-interkonvertierbar ist, ist das Ergebnis ein Zeiger auf b. Andernfalls ist der Zeigerwert unverändert durch die Konvertierung.

Wohin gehe ich damit? Unter der Annahme, pc hält bereits die Adresse eines int (geeignet entsprechend dem oben genannten umgewandelt), dann Gießen der char* zu einem int* über reinterpret_cast wird Ihnen die Adresse des ursprünglichen int geben. Die Note unter dem ersten Absatz sagt so viel aus, und die weiteren Zitate beweisen es. Wenn es nicht die Adresse eines int hält, spielen Sie Roulette und werden wahrscheinlich verlieren. Ihr Programm hat ein undefiniertes Verhalten. Sie sollten Bathsebas Ratschlag auf den Buchstaben folgen.

+0

danke für Ihre Erklärung, ich bin ein neuer Programmierer und finde den Compiler beschweren sich über die alte Art Besetzung in einem alten Projekt.Ich dachte, es könnte eine bessere Möglichkeit, dies zu tun, und ich kam hierher ... Ich hatte viel lernen. – maidamai

6

Das Verhalten bei der Konvertierung, im Allgemeinen ein char* Zeiger auf einen int* Zeiger ist undefined. Dereferenzierung eines solchen Zeigers wird Ihnen weitere Probleme bereiten, da Sie strikte Aliasing Regeln brechen werden. Beachten Sie, dass der C++ Standard sizeof(char*) nicht mit sizeof(int*) identisch ist.

(Man beachte, dass ein Zeiger auf eine unsigned char*int* Umwandeln gut definiert, wenn die unsigned char* Zeiger verweist tatsächlich auf ein int).

Tun Sie es nicht. Je.

+7

Es sei denn, dass 'char *' bereits auf ein 'int' verweist .... Ein legitimes Aliasing – StoryTeller

+0

Sind Sie sicher? 'unsigned char *' ist sicherlich in Ordnung. – Bathsheba

+2

@Bathsheba - Der Zugriff auf den Speicher ist eine Sache (und ich würde "unsigned char" bevorzugen, um auf der sicheren Seite zu sein). Aber nur einen Zeiger zu bekommen und zurückzuwerfen scheint echt. – StoryTeller

7

Wenn Sie das wirklich tun müssen, dann reinterpret_cast ist dein Freund:

char *pc = 0; 
int *pi = 0; 

pi = reinterpret_cast<int*>(pc); 
+5

Die ersten 7 Wörter sind die wichtigsten. – Rotem

+1

@Sean - Ich stimme Rotems Kommentar zu. Sie müssen wirklich die ersten sieben Wörter hervorheben. Es gibt sehr wenige reale Umstände, bei denen "reinterpret_cast" eine bevorzugte Lösung ist, aufgrund der Wahrscheinlichkeit späterer Fälle von undefiniertem Verhalten. – Peter