2014-07-09 19 views
10

von der Standard-C++:Wann ändert reinterpret_cast Bits?

5.2.10.3

Die Kartierung von reinterpret_cast geführt könnte, oder auch nicht, eine Darstellung unterscheidet sich von dem ursprünglichen Wert erzeugen.

Ich wurde auf dieser Website geschult, um zu glauben und dies zu wiederholen. (Auch wenn es möglicherweise nur Quiz ist). Ein reinterpret_cast von float* bis int* ist berechtigt, ein anderes Bitmuster zu erzeugen. Die einzige Garantie ist, dass reinterpret_cast - das Ergebnis zurück zu float* wird das ursprüngliche Bitmuster erzeugen.

Meine Frage: Ist das jemals passiert? Gibt es eine existierende, reale Plattform oder CPU oder Compiler, die tatsächlich reinterpret_cast s zu einem anderen Bitmuster? Wenn nicht, gibt es Situationen in der realen Welt, in denen reinterpret_cast Runtime Overhead hat?

In all meiner Erfahrung mit reinterpret_cast, war die Besetzung eine Richtlinie zur Compiler, nicht die Laufzeit.

+2

Wenn es gibt keine solche Plattform, dann wird diese Frage schwer zu beantworten sein, da ich bezweifle, dass es Leute gibt, die getrost sagen können "Es gibt keine solche Plattform, ich kenne sie alle". Als rein hypothetisches Beispiel könnte es jedoch eine Maschine geben, die eine N-Byte-Speicherausrichtung erfordert und Ersatzbits in Zeigerwerten aufweist, und diese Bits dazu verwenden würde, zusätzliche Informationen zu codieren, die für "float" und "int" unterschiedlich sind * '. Wenn also der Standard das Ändern des Bitmusters nicht erlauben würde, wäre der Cast für diese Architektur unmöglich. – hyde

Antwort

1

Ich habe auf Plattformen gearbeitet, wo char* war größer als int*, und auf Plattformen, wo sie ein anderes Layout hatte, obwohl die Größe der gleiche war.Keine der fraglichen Maschinen ist jedoch heute besonders relevant (obwohl die zweite, die PDP-10, war eine der wichtigsten Maschinen in ihrer Blütezeit). Es ist auch denkbar, dass einige Kompiliermodi auf einem Intel in nativen Modus (oder was verwendete nativen Modus aufgerufen werden) würde „normalisiert“ Zeiger in einem reinterpret_cast, oder sogar eine implizite Konvertierung, um Adressabgleiche zu erleichtern. Es ist auch denkbar (obwohl ich es nicht gesehen habe), dass solche Konvertierungen korrekte Ausrichtung erzwingen, z. eine Umwandlung von char* zu int* könnten die zwei niederwertigen Bits auf 0 Praxis jedoch zwingen, ich glaube nicht, heute, dass Sie sehen eine reinterpret_cast machen alle Änderungen zwischen Datenzeiger Typen wahrscheinlich sind, . Das Problem ist historischer. (Aber ich bin mir nicht sicher über moderne Embedded-Prozessoren. Von dem, was ich verstehe, viele von ihnen sind Wortadressierung, und so, wenn sizeof(int) != sizeof(char), sie sind wahrscheinlich ein spezielles Format müssen char Adresse.)

+0

In meiner begrenzten Erfahrung ändern Mikrocontroller die Zeiger nicht und stürzen stattdessen mit einem Busfehler ab, wenn ein fehlausgerichteter Zeiger dereferenziert wird. Das hat wahrscheinlich etwas damit zu tun, dass die Transformation ohne Laufzeitkosten nicht möglich ist. – nwp

+1

Für diese Situationen erwähnen Sie, "' char * 'ist größer als' int * '", "native Moduszeiger müssen normalisiert werden", "niederwertige Bits müssen auf Null gesetzt werden" - bedeutet das meine Prämisse in der Frage _round trip_ casting muss "das ursprüngliche Bitmuster" erzeugen? –

+0

@nwp Dies ist das Verhalten von Sun CC oder g ++ auf einem Sparc; es ist wahrscheinlich das universelle Verhalten auf einer Maschine mit Byteadressierung. Aber haben alle Embedded-Prozessoren eine Byte-Adressierung? Was ist mit DSPs? Da bin ich mir nicht sicher. Ein Compiler, der versucht, 8-Bit-Bytes auf einem 32-Bit-DSP ohne Byte-Adressierung zu implementieren, muss die zusätzlichen Bits setzen, um das Byte irgendwo außerhalb der normalen Hardware-Adresse auszuwählen. –

5

Zeiger können grundsätzlich unterschiedliche Größen haben. Der größte Zeiger, wenn es einen Unterschied gibt (abgesehen von Element-Zeigern, sprechen über echte Zeiger), ist char*, da ein char definitionsgemäß ein Byte ist und irgendwo sein kann, keine Ausrichtung. void* muss char* darstellen können.

Auf einem System mit weniger Bits als int*char* Verwendung reinterpret gieße in diese Richtung könnte ein bisschen riskant.

Ich denke mit diesen Zeigern (heh) können Sie dies im Standard finden. Es ist die Anforderung über void* groß genug für jeden Zeiger und die Sache über die Ausrichtung: je strenger/größer, desto weniger Bits benötigt für Zeiger auf diesen Typ. Aber ich habe noch nie von einem bestehenden System gehört, wo es solche Unterschiede gibt.


Standardese bezüglich void* Lage zu repräsentieren char*:

C++ 11 §3.9.2/4:


Ein Zeiger auf cv, Qualifizierte (3.9.3) oder cv -unqualifiziert void kann verwendet werden , um auf Objekte unbekannten Typs zu zeigen. Ein solcher Zeiger muss in der Lage sein, jedes Objekt Zeiger zu halten.Ein Objekt des Typ cvvoid* dort die gleichen Darstellung und Ausrichtungsanforderungen als cvchar*

Die hat “ jeder Objektzeiger ” impliziert vage, dass es verschiedene Größen von Zeigern.


Standaredese in Bezug auf die Ausrichtung von referenten:

C++ 11 §5.2.10/7:


ein Objektzeiger kann explizit auf ein Objekt überführt werden Zeiger eines anderen Typs. Wenn ein prvalue v des Typs „Zeiger auf T1“ auf den Typ umgewandelt wird, „Zeiger auf cvT2“, ist das Ergebnis is static_cast<cvT2*>(static_cast<cvvoid*>(v)) wenn beide T1 und T2 sind Standard-Layout-Typen (3.9) und Die Ausrichtung Anforderungen von T2 sind nicht strenger als die von T1, oder wenn einer der beiden Typen void ist. Umwandeln eines prvalue vom Typ „Zeiger auf T1“ auf den Typ „Zeiger auf T2“ (wobei T1 und T2 Objekt sind Typen und wo die Ausrichtung Anforderungen T2 nicht strenger sind als diejenigen von T1) und zurück in seine ursprüngliche Typ Ausbeuten der ursprüngliche Zeiger Wert. Das Ergebnis einer anderen derartigen Zeigerumwandlung ist nicht spezifiziert.

Es ’ s erwähnenswert, dass später im Standard gibt es eine gewisse Unterstützung für C-Stil-Emulation von Klassenableitung, die offenbar die “ über andere ” am Ende widerspricht:

C++ §9.2 11/20,


ein Zeiger auf eine struct Objekt Standard-Layout, umgewandelt in geeigneter Weise eineVerwendung 210, zeigt auf seinen ursprünglichen Member (oder wenn dieses Mitglied ein Bit-Feld ist, dann auf die Einheit, in der es sich befindet) und umgekehrt.

In diesem Fall sind die beiden Objekte notwendigerweise die gleiche Ausrichtung haben, während die vorherige zitierten Absatz nur über die Ausrichtung der Typen – gesprochen, aber deutlich die formale wenig Widerspruch ist kein praktisches Problem, wie ich es sehe.

+2

Ich nahm an einer Diskussion über die Mill CPU teil, wo einer der Teammitglieder sagte, dass Ivan Godard an einer "Fließzeiger" -Darstellung arbeite, die es ermöglichen würde, * einige * außerhalb der Grenzen liegende Zugriffe zu erkennen. In diesem Fall würde die innere Darstellung (in der CPU) des Zeigers die unbenutzten Bits verwenden, um den Bereich (irgendwie) auszudrücken. Es war unklar in der Diskussion, wie weit sie waren und ob dies außerhalb der CPU zugänglich wäre, aber zumindest denken sie darüber nach. –

Verwandte Themen