2012-04-14 21 views
31

Offensichtlich betrachtet der Compiler sie als nicht verwandte Typen und daher ist reinterpret_cast erforderlich. Warum ist das die Regel?Warum kann ich nicht zwischen char * und unsigned char * static_cast?

+0

Ich nehme den SHA-1-Hash einer Zeichenfolge. 'c_str()' gibt ein 'const char *' zurück und die SHA-1 Funktion nimmt ein 'const unsigned char *' als Argument. – Nick

+0

Und was erwarten Sie, wenn diese Zeichenfolge negative Zeichenwerte enthält? – Pubby

+0

Ich erwarte, dass jeder negative Wert "c" zu "c + 256" wird, wie es bei der Konvertierung eines vorzeichenbehafteten Bytes in einen vorzeichenlosen Byte Standard ist. Ehrlich gesagt, mache ich gerade die Umwandlung, um einen Hash-Wert zu berechnen. Es ist mir egal, wie sie konvertiert werden, solange sie jedes Mal auf die gleiche Weise konvertiert werden. – Nick

Antwort

26

Sie sind völlig verschiedene Typen siehe Standard:

3.9.1 Grundtypen [basic.fundamental]

1 Objekte deklariert als Zeichen char) ist ein Mitglied der zu Speicher groß genug sein, den grundlegenden Zeichensatz der Implementierung. Wenn ein Zeichen aus diesem Satz in einem Zeichenobjekt gespeichert wird, ist der integrale Wert dieses Zeichenobjekts gleich dem Wert der einzelnen Zeichenliteralform dieses Zeichens. Es ist Implementation-definiert, ob ein Char-Objekt negative Werte enthalten kann. Zeichen können explizit ohne Vorzeichen oder
signiert werden.Plain char, signed char und unsigned char sind drei verschiedene Typen. Ein Zeichen, ein Zeichen mit Vorzeichen und ein Zeichen ohne Vorzeichen belegen die gleiche Menge an Speicher und haben die gleiche Ausrichtung Anforderungen (basic.types); das heißt, sie haben das gleiche Objekt Darstellung. Bei Zeichentypen sind alle Bits des Objekts
an der Wertdarstellung beteiligt. Bei unsignierten Zeichentypen stehen alle möglichen Bitmuster der Wertdarstellung für Zahlen. Diese Anforderungen gelten nicht für andere Typen. In jeder bestimmten Implementierung kann ein einfaches Zeichenobjekt entweder die gleichen Werte wie ein vorzeichenbehaftetes Zeichen oder ein unsigniertes Zeichen annehmen; welcher ist Implementierung definiert.

dazu So analog ist auch, warum die folgenden fehlschlägt:

unsigned int* a = new unsigned int(10); 
int* b = static_cast<int*>(a); // error different types 

a und b sind völlig verschiedene Arten, wirklich das, was Sie fragen, warum ist static_cast so restriktiv, wenn es ohne die folgende ausführen können Problem

unsigned int a = new unsigned int(10); 
int b = static_cast<int>(a); // OK but may result in loss of precision 

und warum kann es nicht ableiten, dass die Zieltypen die gleiche Bit-Feldbreite sind und dargestellt werden? Es kann dies für skalare Typen tun, aber für Zeiger, es sei denn, das Ziel wird von der Quelle abgeleitet und Sie möchten einen Downcast durchführen, dann wird das Gießen zwischen Zeigern nicht funktionieren.

Bjarne Stroustrop erklärt, warum static_cast ‚s in diesem Link nützlich ist: http://www.stroustrup.com/bs_faq2.html#static-cast aber in verkürzter Form ist es für den Benutzer klar zu sagen, was ihre Absichten sind und dem Compiler die Möglichkeit zu geben, zu überprüfen, dass das, was Sie beabsichtigen, sein kann erreicht, da static_cast keine Umwandlung zwischen verschiedenen Zeigertypen unterstützt, dann kann der Compiler diesen Fehler abfangen, um den Benutzer zu warnen, und wenn er diese Konvertierung wirklich durchführen möchte, dann sollte er reinterpret_cast verwenden.

+0

thx für die Angabe des Standards hier. Ich habe es nicht verfügbar. –

+0

Also, wenn sie unterschiedliche Typen sind, warum erlaubt der Compiler den Cast 'unsigned char a = 255; char b = static_cast (a); '? – Nick

+2

aus dem gleichen Grund können Sie static_cast von doubles zu ints und der andere Weg, was Sie nicht tun können, ist statisch_cast double * to int *, die Zeigertypen sind unterschiedlich, aber Sie können von einem Wert in einen anderen mit der Einschränkung, dass es kann ein Verlust an Genauigkeit sein – EdChum

7

Sie versuchen, nicht verwandte Zeiger mit einem static_cast zu konvertieren. Dafür ist static_cast nicht da. Hier können Sie sehen: Type Casting.

Mit static_cast können Sie numerische Daten (z. B. char zu unsigned char sollte funktionieren) oder Zeiger auf verwandte Klassen (durch Vererbung verwandt) konvertieren. Dies ist beides nicht der Fall. Sie möchten einen nicht verwandten Zeiger in einen anderen konvertieren, sodass Sie reinterpret_cast verwenden müssen.

Im Grunde ist das, was Sie versuchen zu tun, für den Compiler der gleiche wie beim Versuch, ein char * in ein void * umzuwandeln.


Ok, hier einige zusätzliche Gedanken, warum dies grundsätzlich falsch ist. Mit static_cast können numerische Typen ineinander umgewandelt werden. So ist es vollkommen legal folgendes zu schreiben:

char x = 5; 
unsigned char y = static_cast<unsigned char>(x); 

was ist auch möglich:

double d = 1.2; 
int i = static_cast<int>(d); 

Wenn Sie an diesem Code in Assembler aussehen werden Sie sehen, dass die zweite Besetzung ist nicht nur ein Wieder - Interpretation des Bitmusters von d, stattdessen werden hier einige Assembleranweisungen für Konvertierungen eingefügt.

Jetzt, wenn wir dieses Verhalten auf Arrays erweitern, der Fall, wo einfach eine andere Art der Interpretation des Bitmusters ausreicht, könnte es funktionieren. Aber was ist mit Casting von Doppelfeldern zu Arrays von Ints? Das ist, wo Sie entweder erklären müssen, dass Sie einfach eine Neuinterpretation der Bitmuster wollen - es gibt einen Mechanismus dafür, der reinterpret_cast genannt wird, oder Sie müssen etwas zusätzliche Arbeit machen. Wie Sie sehen können, ist die einfache Erweiterung von static_cast für Pointer/Arrays nicht ausreichend, da sie sich ähnlich wie static_casting-Einzelwerte der Typen verhalten muss. Dies erfordert manchmal zusätzlichen Code und es ist nicht klar definierbar, wie dies für Arrays zu tun ist. In Ihrem Fall - Stopp bei \ 0 - weil es die Konvention ist? Dies ist nicht ausreichend für Nicht-String-Fälle (Anzahl). Was passiert, wenn sich die Größe des Datentyps ändert (z. B. int vs. double auf x86-32bit)?

Das gewünschte Verhalten kann nicht ordnungsgemäß für alle Anwendungsfälle definiert werden, daher liegt es nicht im C++ - Standard. Ansonsten müsstest du dir Dinge merken wie: "Ich kann diesen Typ auf den anderen übertragen, solange sie vom Typ Integer sind, die gleiche Breite haben und ...". Auf diese Weise ist es völlig klar - entweder sind sie verwandte Klassen - dann können Sie die Zeiger, oder sie sind numerische Typen - dann können Sie die Werte werfen.

+0

Ich habe in meinem ersten Beitrag bestätigt, dass der Compiler sagt, dass sie nicht verwandte Zeiger sind. Was ich wissen will, ist _why_. Es scheint mir, dass, wenn "T1" mit "T2" "verwandt" ist, "T1 *" mit "T2 *" "verwandt" sein sollte. Warum klingen diese Regeln nicht (für primitive Typen)? – Nick

+3

@Nick es ist nicht "irgendwie verwandt", sondern "verwandte Klassen". Wie Sie sagten, sind char und unsigned char Primitive - keine Klassen. Das ist der Grund - und das habe ich gesagt, wenn Sie aufmerksam lesen. Sie haben Recht - wenn die Klasse T1 mit der Klasse T2 zusammenhängt, können Sie mit static_cast T1 * in T2 * umwandeln. Das ist nicht was du tust. char steht nicht im Zusammenhang mit dem unsignierten Zeichen im Zusammenhang mit dem C++ - Standard. –

+0

Wenn Sie jedoch den Zeiger ablegen, hat der Compiler kein Problem zwischen den Grundtypen, z. 'unsigned char a = 255; char b = static_cast (a); 'Es scheint ein bisschen seltsam, denn wenn' T1' und 'T2' Klassen sind, ist die Umwandlung zwischen Zeigern nicht sound, da man so etwas machen könnte: ' Klasse A; ' 'Klasse B: public A;' 'B * b = new B [4];' 'b [0] = B();' 'a * a = static_cast (b);' 'a [1] = A(); ' ' B b1 = b [1]; // oops' Es scheint als wäre die _only_ Zeit, in der die Besetzung sicher sein sollte, zwischen primitiven Typen. – Nick

4

Abgesehen davon, dass Zeiger, unsigned char * und char * haben nichts gemein (EdChum bereits die Tatsache erwähnt, dass char, signed char und unsigned char drei verschiedene Typen). Sie könnten dasselbe für Foo * und Bar * Zeigertypen zu irgendwelchen unähnlichen Strukturen sagen.

static_cast bedeutet, dass ein Zeiger des Quelltyps als Zeiger des Zieltyps verwendet werden kann, der eine Untertypbeziehung erfordert. Daher kann es nicht im Zusammenhang mit Ihrer Frage verwendet werden; Was Sie brauchen, ist entweder reinterpret_cast, was genau das tut, was Sie wollen oder ein C-Style-Cast.