Ich versuche, char als positiven Wert zu drucken:
char ch = 212;
printf("%u", ch);
aber ich bekomme:
4294967252
Wie kann ich bekommen 212
in der Ausgabe?
Anton
Ich versuche, char als positiven Wert zu drucken:
char ch = 212;
printf("%u", ch);
aber ich bekomme:
4294967252
Wie kann ich bekommen 212
in der Ausgabe?
Erklären Sie Ihre ch
wie
unsigned char ch = 212 ;
Und Ihr printf wird funktionieren.
Sogar mit ch
gewechselt zu unsigned char
, ist das Verhalten des Codes nicht durch den C-Standard definiert. Dies liegt daran, dass die unsigned char
wird zu einem befördert int
(in normalen C-Implementierungen), so an int
übergeben wird printf
für den Spezifizierer %u
. Jedoch, %u
erwartet ein unsigned int
sodass die Typen nicht übereinstimmen und der C-Standard das Verhalten nicht definiert.
– Eric Postpischil
1. April 2013 um 13:32 Uhr
Ihr Kommentar ist falsch. Der C11-Standard besagt, dass der Konvertierungsbezeichner vom gleichen Typ wie die Funktion sein muss argument
selbst, nicht der geförderte Typ. Auf diesen Punkt wird auch in der Beschreibung der speziell eingegangen hh
Längenmodifikator: “Das Argument wurde gemäß den Integer-Promotions hochgestuft, aber sein Wert muss vor dem Drucken in ein Zeichen mit Vorzeichen oder ohne Vorzeichen konvertiert werden.”
– andypea
13. April 2014 um 23:10 Uhr
Funktionierte nur nach expliziter Umwandlung in ` unsigned int` bei der Übergabe an prtinf()
. Das Hinzufügen von -std=c11 zum gcc-4.8.4-Befehl, um den Standard durchzusetzen, hatte keine Wirkung.
– ypx
23. Oktober 2015 um 9:42 Uhr
@EricPostpischil Was genau sagt %d aus? Und was sagt der Spezifizierer %u aus?
– Suraj Jain
28. Dezember 2016 um 7:49 Uhr
@andrew.punnett: Das Funktionsargument ist der beförderte Wert; es hat den Typ, der sich aus den ganzzahligen Beförderungen ergibt, gemäß C 2011 6.5.2.2 6. Im Fall von hh
ja, der Standard sagt uns, dass der Typ vor der Beförderung a sein kann signed char
oder unsigned char
. Es bedeutet, dass die ch
wird noch zu einem befördert int
aber die Konvertierung %hhu
erwartet das. Dies ist jedoch für diese Situation nicht relevant, in der hh
ist nicht dabei printf(%u, ch)
.
– Eric Postpischil
29. Dezember 2016 um 12:33 Uhr
Sergej Kalinitschenko
Dies liegt daran, dass in diesem Fall die char
Typ ist auf Ihrem System signiert*. In diesem Fall werden die Daten während der Standardkonvertierungen vorzeichenerweitert, während die Daten mit einer variablen Anzahl von Argumenten an die Funktion übergeben werden. Da 212 größer als 0x80 ist, wird es als negativ behandelt, %u
interpretiert die Zahl als große positive Zahl:
212 = 0xD4
Wenn es vorzeichenerweitert ist, FF
s werden Ihrer Nummer vorangestellt, also wird es
0xFFFFFFD4 = 4294967252
Das ist die Zahl, die gedruckt wird.
Beachten Sie, dass dieses Verhalten spezifisch für Ihre Implementierung ist. Gemäß C99-Spezifikation alle char
Typen werden zu (signiert) befördert int
weil ein int
kann alle Werte von a darstellen char
signiert oder unsigniert:
6.1.1.2: Wenn ein
int
alle Werte des ursprünglichen Typs darstellen kann, wird der Wert in ein umgewandeltint
; andernfalls wird es in ein umgewandeltunsigned int
.
Dies führt zum Passieren einer int
zu einem Formatbezeichner %u
die eine erwartet unsigned int
.
Um undefiniertes Verhalten in Ihrem Programm zu vermeiden, fügen Sie explizite Typumwandlungen wie folgt hinzu:
unsigned char ch = (unsigned char)212;
printf("%u", (unsigned int)ch);
* Im Allgemeinen belässt der Standard die Signiertheit von char
bis zur Umsetzung. Siehe diese Frage für weitere Details.
Diese Antwort ist verworren und ungenau. Die Sätze über die Zeichenerweiterung und die Behandlung von 212 werden ohne Kontext dargestellt, wobei nicht erklärt wird, wo sie zutreffen (der frühere Satz gilt für eine spätere Operation, ganzzahlige Beförderung des char
wenn es als Argument verwendet wird, während der spätere Satz für eine frühere Operation gilt, Initialisierung des char
mit einem int
).
– Eric Postpischil
1. April 2013 um 13:12 Uhr
Die Aussage, dass 212 als negativ behandelt wird, weil sie größer als 0x80 ist, ist falsch. Initialisieren Sie zunächst eine signierte char
mit 212 verursacht in den meisten C-Implementierungen einen ganzzahligen Überlauf, sodass das Verhalten undefiniert ist. In vielen C-Implementierungen führt dies zu einer Kürzung der Zweierkomplementdarstellung von 212 auf acht Bits, was dazu führt, dass die Bits als negativer Wert interpretiert werden, weil das 0x80-Bit gesetzt ist, nicht weil der Anfangswert größer als 0x80 ist (Gegenbeispiele umfassen 0x80 und 0x100).
– Eric Postpischil
1. April 2013 um 13:13 Uhr
Nach der Initialisierung der char
es wird als Argument für verwendet printf
. Die ganzzahligen Beförderungen werden durchgeführt, was zu einem Negativ führt int
weitergegeben werden printf
. Auch hier verwenden viele C-Implementierungen das Zweierkomplement, sodass eine Vorzeichenerweiterung durchgeführt wird, wie diese Antwort sagt. Konvertieren Sie den Wert in unsigned
an diesem Punkt würde eine große positive Zahl ergeben. Diese Antwort erklärt jedoch nicht, dass das tatsächliche Verhalten durch den C-Standard nicht definiert ist, da an int
wird für einen Bezeichner von übergeben %u
die eine erwartet unsigned int
.
– Eric Postpischil
1. April 2013 um 13:14 Uhr
@EricPostpischil Danke für deine Kommentare! Ich habe die Diskrepanz zwischen dem Argument und dem Formatbezeichner übersehen. Dies ist jetzt behoben.
– Sergej Kalinitschenko
1. April 2013 um 13:51 Uhr
@dasblinkenlight char
passt nicht garantiert in den Typ int
seit char
möglicherweise auf dasselbe Verhalten wie definiert worden sein unsigned char
. Nur eine ganze Zahl mit demselben Vorzeichen, aber einem kleineren ganzzahligen Konvertierungsrang hat garantiert einen Wertebereich, der ein Unterbereich des Wertebereichs des anderen Typs ist (Abschnitt 6.2.5 Absatz 8 des C99-Standards). Deswegen, unsigned char
könnte theoretisch eine Bandbreite haben, die so groß ist wie unsigned int
aufgrund seiner Signiertheit und der ganzzahligen Konvertierungsränge.
– Wilhelm Grau
25. Juli 2013 um 21:23 Uhr
Eric Postpischil
Es gibt zwei Fehler in diesem Code. Erstens, in den meisten C-Implementierungen mit signed char
es liegt ein Problem vor char ch = 212
weil 212 nicht in ein 8-Bit-Zeichen passt char
, und der C-Standard definiert das Verhalten nicht vollständig (es erfordert, dass die Implementierung das Verhalten definiert). Es sollte stattdessen sein:
unsigned char ch = 212;
Zweitens, hinein printf("%u",ch)
, ch
wird zu einem befördert int
in normalen C-Implementierungen. Allerdings ist die %u
Bezeichner erwartet ein unsigned int
, und der C-Standard definiert kein Verhalten, wenn der falsche Typ übergeben wird. Es sollte stattdessen sein:
printf("%hhu", ch);
(Zum %hhu
, printf
erwartet ein unsigned char
das wurde in normalen C-Implementierungen zu befördert int
.)
Ich würde vorschlagen, static_cast anstelle von Cast im alten Stil zu verwenden
– Shital Shah
8. Juni 2016 um 5:23 Uhr
@ShitalShah: Die Frage ist mit C gekennzeichnet, nicht mit C++. C hat keinen static_cast-Operator.
– Eric Postpischil
29. Dezember 2016 um 12:39 Uhr
Ah.. nicht gesehen.
– Shital Shah
29. Dezember 2016 um 22:27 Uhr
Falls Sie die Erklärung aus irgendeinem Grund nicht ändern können, haben Sie folgende Möglichkeiten:
char ch = 212;
printf("%d", (unsigned char) ch);
banarun
Der Zeichenbereich liegt zwischen 127 und -128. Wenn Sie 212 zuweisen, speichert ch -44 (212-128-128) und nicht 212. Wenn Sie also versuchen, eine negative Zahl als unsigned zu drucken, erhalten Sie (MAX-Wert von unsigned int)-abs(number) was in diesem Fall 4294967252 ist
Wenn Sie also 212 so speichern möchten, wie es in ch ist, können Sie ch nur als deklarieren
unsigned char ch;
jetzt ist der Bereich von ch 0 bis 255.
“Der Zeichenbereich ist 127 bis -128.” — Nein, der Bereich ist implementierungsdefiniert.
– Jim Balter
1. April 2013 um 2:17 Uhr
Ich meine, was ich gesagt habe … es war ziemlich klar. Ein Zeichen ist nicht einmal unbedingt 8 Bit lang, geschweige denn unbedingt signiert.
– Jim Balter
1. April 2013 um 18:45 Uhr
Diese Antwort ist offensichtlich falsch. Der Bereich von Char tut variieren, sind es auf ARM-Plattformen üblicherweise 8 Bit ohne Vorzeichen.
– Antti Haapala – Слава Україні
26. Februar 2019 um 7:29 Uhr
Trevor Hickey
Da char
ist standardmäßig signed
deklariert, was bedeutet, dass der Bereich der Variablen ist
-127 bis +127>
Ihr Wert ist übergelaufen. Um den gewünschten Wert zu erhalten, müssen Sie deklarieren unsigned
Modifikator. der Modifikator (unsigned
) Bereich ist:
0 to 255
Um den Bereich eines beliebigen Datentyps zu erhalten, folgen Sie dem Prozess 2^bit
Beispiel char
8 Bit Länge hat, um seine Reichweite gerade zu bekommen 2 ^(power) 8
.
“Der Zeichenbereich ist 127 bis -128.” — Nein, der Bereich ist implementierungsdefiniert.
– Jim Balter
1. April 2013 um 2:17 Uhr
Ich meine, was ich gesagt habe … es war ziemlich klar. Ein Zeichen ist nicht einmal unbedingt 8 Bit lang, geschweige denn unbedingt signiert.
– Jim Balter
1. April 2013 um 18:45 Uhr
Diese Antwort ist offensichtlich falsch. Der Bereich von Char tut variieren, sind es auf ARM-Plattformen üblicherweise 8 Bit ohne Vorzeichen.
– Antti Haapala – Слава Україні
26. Februar 2019 um 7:29 Uhr