Anscheinend betrachtet der Compiler sie als nicht verwandte Typen und daher reinterpret_cast
Wird benötigt. Warum ist das die Regel?
Warum kann ich kein static_cast zwischen char * und unsigned char * durchführen?
EdChum
Sie sind völlig unterschiedliche Typen siehe Standard:
3.9.1 Grundtypen [basic.fundamental]
1 Als Zeichen char deklarierte Objekte müssen groß genug sein, um jedes Mitglied des grundlegenden Zeichensatzes der Implementierung zu speichern. Wenn ein Zeichen aus diesem Satz in einem Zeichenobjekt gespeichert wird, ist der ganzzahlige Wert dieses Zeichenobjekts gleich dem Wert der Einzelzeichen-Literalform dieses Zeichens. Es wird durch die Implementierung definiert, ob ein char-Objekt negative Werte enthalten kann. Zeichen können explizit ohne Vorzeichen deklariert werden oder
unterzeichnet. Einfaches Zeichen, Zeichen mit Vorzeichen und Zeichen ohne Vorzeichen sind drei verschiedene Typen. Ein Zeichen, ein Zeichen mit Vorzeichen und ein Zeichen ohne Vorzeichen belegen den gleichen Speicherplatz und haben die gleichen Ausrichtungsanforderungen (Grundtypen); das heißt, sie haben dieselbe Objektdarstellung. Bei Zeichentypen alle Bits des Objekts
Repräsentation an der Wertrepräsentation teilnehmen. Bei vorzeichenlosen Zeichentypen stellen alle möglichen Bitmuster der Wertdarstellung Zahlen dar. Diese Anforderungen gelten nicht für andere Typen. In einer bestimmten Implementierung kann ein einfaches char-Objekt entweder die gleichen Werte wie ein vorzeichenbehaftetes oder ein vorzeichenloses Zeichen annehmen; welche ist implementierungsdefiniert.
Analog dazu schlägt auch folgendes fehl:
unsigned int* a = new unsigned int(10);
int* b = static_cast<int*>(a); // error different types
a
und b
sind völlig unterschiedliche Typen, Sie fragen sich wirklich, warum static_cast so restriktiv ist, wenn es die folgenden problemlos ausführen kann
unsigned int a = new unsigned int(10);
int b = static_cast<int>(a); // OK but may result in loss of precision
und warum kann daraus nicht abgeleitet werden, dass die Zieltypen die gleiche Bitfeldbreite haben und dargestellt werden können? Dies ist für skalare Typen möglich, aber für Zeiger, es sei denn, das Ziel wird von der Quelle abgeleitet und Sie möchten einen Downcast durchführen, dann funktioniert das Umwandeln zwischen Zeigern nicht.
Bjarne Stroustrop erklärt warum static_cast
‘s sind in diesem Link nützlich: http://www.stroustrup.com/bs_faq2.html#static-cast aber in abgekürzter Form ist es Sache des Benutzers, seine Absichten klar zu formulieren und dem Compiler die Möglichkeit zu geben, zu überprüfen, ob das von Ihnen beabsichtigte erreicht werden kann, da static_cast
unterstützt das Casting zwischen verschiedenen Zeigertypen nicht, dann kann der Compiler diesen Fehler abfangen, um den Benutzer zu warnen, und wenn er diese Konvertierung wirklich durchführen möchte, sollte er verwenden reinterpret_cast
.
-
thx für die Angabe des Standards hier. Ich habe es nicht verfügbar.
– Tobias Langner
14. April ’12 um 8:27
-
Aus dem gleichen Grund können Sie static_cast von doubles zu ints und umgekehrt, was Sie nicht tun können, ist static_cast double* zu int* ein Verlust an Präzision
– EdChum
14. April ’12 um 9:02
-
@Nick: Auch mit
int
undfloat
. Sie können die gleiche Größe haben, aber wenn Sie eineint
, dann versuche es wie a . zu lesenfloat
, was du bekommst, hängt davon ab, wie genaufloat
wird im Speicher abgelegt. Und da die Spezifikation dies nicht tut sagen wiefloat
wird im Speicher abgelegt, die Spezifikation kann nicht definieren, was dieint
sieht aus wie. Denken Sie daran: Der C++-Standard existiert, um Garantien für das zu bieten, was Sie erhalten. Um dieses Verhalten zu definieren, müsste der Standard detailliert beschreiben, wiefloat
im Gedächtnis angelegt ist, sowie wieint
ist im Gedächtnis angelegt.– Nicol Bolas
14. April ’12 um 20:22
-
@Nick: Kurz gesagt: Sie verwechseln das Konzept “was auf echten Maschinen passiert” mit “was die Spezifikation erfordert”.
– Nicol Bolas
14. April ’12 um 20:23
-
Die Spezifikation sagt nicht, dass das höchstwertige Bit das Vorzeichenbit sein muss, daher könnte eine Implementierung das niedrigstwertige Bit haben. Wenn dies der Fall wäre, würde der Compiler, wenn er ein unsigned char mit dem Wert 1 in ein signed char umwandelt, wissen, dass er die Bits nach links um 1 verschieben muss, um das Vorzeichenbit zu berücksichtigen. Aber bei einem unsigned char* und char* ist es nicht die Aufgabe des Casts, die Werte an der Position des Pointers anzupassen. Es wüsste sowieso nicht, wie viele Zeichen angepasst werden müssen.
– Cemafor
12. März ’15 um 22:59
Tobias Langner
Sie versuchen, nicht verwandte Zeiger mit einem static_cast zu konvertieren. Dafür ist static_cast nicht da. Hier sieht man: Typ Gießen.
Mit static_cast können Sie numerische Daten (zB char in unsigned char sollte funktionieren) oder Zeiger auf verwandte Klassen (durch eine Vererbung verwandt) konvertieren. Dies ist beides nicht der Fall. Sie möchten einen unabhängigen Zeiger in einen anderen konvertieren, daher müssen Sie reinterpret_cast verwenden.
Im Grunde ist das, was Sie versuchen, für den Compiler dasselbe wie der Versuch, ein char * in ein void * umzuwandeln.
Ok, hier noch ein paar zusätzliche Gedanken, warum es grundsätzlich falsch ist, dies zuzulassen. Mit static_cast können numerische Typen ineinander umgewandelt werden. Es ist also völlig 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 sich diesen Code in Assembler ansehen, werden Sie feststellen, dass der zweite Cast keine bloße Neuinterpretation des Bitmusters von d ist, sondern hier einige Assembler-Anweisungen für Konvertierungen eingefügt werden.
Wenn wir dieses Verhalten nun auf Arrays ausdehnen, könnte es in dem Fall funktionieren, in dem einfach eine andere Art der Interpretation des Bitmusters ausreicht. Aber was ist mit der Umwandlung von Arrays von Doubles in Arrays von Ints? Hier müssen Sie entweder erklären, dass Sie einfach eine Neuinterpretation der Bitmuster wünschen – dafür gibt es einen Mechanismus namens reinterpret_cast, oder Sie müssen zusätzliche Arbeit leisten. Wie Sie sehen, reicht eine einfache Erweiterung des static_cast für Zeiger / Arrays nicht aus, da es sich ähnlich verhalten muss wie das statische_casting einzelner Werte der Typen. Dies erfordert manchmal zusätzlichen Code, und es ist nicht klar, wie dies für Arrays erfolgen soll. In Ihrem Fall – aufhören bei – weil es die Konvention ist? Dies ist für Nicht-String-Fälle (Zahl) nicht ausreichend. Was passiert, wenn sich die Größe des Datentyps ändert (zB int vs. double auf x86-32bit)?
Das gewünschte Verhalten kann nicht für alle Anwendungsfälle richtig definiert werden, deshalb ist es nicht im C++-Standard enthalten. Andernfalls müssten Sie sich Dinge merken wie: “Ich kann diesen Typ in den anderen umwandeln, solange sie vom Typ Integer sind, die gleiche Breite haben und …”. Auf diese Weise ist es völlig klar – entweder sind es verwandte KLASSEN – dann können Sie die Zeiger umwandeln, oder es handelt sich um numerische Typen – dann können Sie die Werte umwandeln.
-
Ich habe in meinem Eröffnungspost bestätigt, dass der Compiler sagt, dass es sich um unabhängige Zeiger handelt. Was ich wissen möchte ist warum. Es scheint mir, wenn
T1
bezieht sich aufT2
, dannT1 *
sollte “verwandt” sein mitT2 *
. Warum ist diese Eingaberegel nicht korrekt (für primitive Typen)?– Nick
14. April ’12 um 7:49
-
@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 genau lesen. Sie haben Recht – wenn Klasse T1 mit Klasse T2 verwandt ist, können Sie static_cast verwenden, um T1* in T2* zu konvertieren. Dies ist nicht das, was Sie tun. char steht nicht im Zusammenhang mit unsigned char im Sinne der vom C++-Standard geforderten Relation.
– Tobias Langner
14. April ’12 um 8:24
-
Wenn Sie jedoch den Zeiger fallen lassen, hat der Compiler keine Probleme beim Casting zwischen primitiven Typen, z
unsigned char a = 255; char b = static_cast<char>(a);
Es scheint ein bisschen seltsam, denn wennT1
undT2
Klassen sind, ist die Umwandlung zwischen Zeigern nicht korrekt, da Sie Folgendes tun könnten:class A;
class B : public A;
B *b = new B[4];
b[0] = B();
A *a = static_cast<A *>(b);
a[1] = A();
B b1 = b[1]; // oops
Es scheint, als ob nur Die Zeit, zu der die Besetzung sicher sein sollte, liegt zwischen primitiven Typen.– Nick
14. April ’12 um 8:37
-
ja – und das Verhalten dafür ist klar und gut definiert. Sie haben einige Regeln, wie Sie einen numerischen Typ in den anderen umwandeln. Dies kann so einfach sein wie das Kopieren des Bitmusters in den neuen Speicher oder so kompliziert wie das Umwandeln eines Doubles in ein Int. Trotzdem – es ist nur für einen Wert und daher leicht definierbar. Siehe meine Erklärung oben. Der static_cast hat 2 völlig unterschiedliche Verwendungen, je nachdem, ob der Typ ein Zeigertyp ist oder nicht. Sie hätten es für die 2 Anwendungsfälle anders benennen sollen (zB static_cast & numerische_cast).
– Tobias Langner
14. April ’12 um 10:59
Abgesehen davon, dass sie Hinweise sind, unsigned char *
und char *
nichts gemeinsam haben (EdChum hat bereits erwähnt, dass char
, signed char
und unsigned char
sind drei verschiedene Typen). Das gleiche könnte man auch sagen Foo *
und Bar *
Zeigertypen auf unterschiedliche Strukturen.
static_cast
bedeutet, dass ein Zeiger des Quelltyps als Zeiger des Zieltyps verwendet werden kann, was eine Untertypbeziehung erfordert. Daher kann es nicht im Kontext Ihrer Frage verwendet werden; was du brauchst ist entweder reinterpret_cast
die genau das tut, was Sie wollen, oder eine Besetzung im C-Stil.
.
Ich nehme den SHA-1-Hash eines Strings.
c_str()
gibt a . zurückconst char *
und die SHA-1-Funktion nimmt aconst unsigned char *
als Argument.– Nick
14. April ’12 um 7:36
Und was erwarten Sie, wenn diese Zeichenfolge negative Zeichenwerte enthält?
– Pubby
14. April ’12 um 7:41
Ich erwarte jeden negativen Wert
c
werdenc + 256
, wie es beim Konvertieren eines vorzeichenbehafteten Bytes in ein vorzeichenloses üblich ist. Ehrlich gesagt mache ich nur die Konvertierung, 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
14. April ’12 um 7:46
@Nick: Konvertieren eines
char
zu einemunsigned char
ist eine Konvertierung. Konvertierenchar *
zuunsigned char*
und dann die Elemente lesen vorausgesetzt dass sie konvertiert wurden, wenn sie es nicht getan haben, ist sehr unterschiedlich. Es funktioniert auf einem System, bei dem die Konvertierung nicht wirklich eine Änderung der Darstellung erfordert (zB auf einem Zweier-Komplement-System), aber da dies eine implementierungsspezifische Annahme ist, ist es angemessen, dass eine explizitereinterpret_cast
Wird benötigt.– CB Bailey
14. April ’12 um 10:38