Wofür wird in C/C++ ein unsigned char
verwendet? Wie unterscheidet es sich von einem normalen char
?
In C++ gibt es drei unterschiedliche Zeichentypen:
char
signed char
unsigned char
Wenn Sie Zeichentypen für Text verwenden, verwenden Sie das nicht qualifizierte char
:
'a'
oder '0'
."abcde"
bestehen.Es funktioniert auch als Zahlenwert, es ist jedoch nicht festgelegt, ob dieser Wert als vorzeichenbehaftet oder nicht vorzeichenbehaftet behandelt wird. Passen Sie auf Zeichenvergleiche durch Ungleichungen auf - auch wenn Sie sich auf ASCII (0-127) beschränken, sind Sie in etwa sicher.
Wenn Sie Zeichentypen als Zahlen verwenden, verwenden Sie:
signed char
, wodurch Sie mindestens den Bereich von -127 bis 127 erhalten. (-128 bis 127 ist üblich)unsigned char
, wodurch Sie mindestens den Bereich von 0 bis 255 erhalten."Zumindest", da der C++ - Standard nur den minimalen Wertebereich angibt, den jeder numerische Typ abdecken muss. sizeof (char)
muss 1 sein (d. h. ein Byte), aber ein Byte könnte theoretisch zum Beispiel 32 Bits sein. sizeof
würde immer noch die Größe von 1
angeben - was bedeutet, dass Sie eine sizeof (char) == sizeof (long) == 1
haben könnten.
Dies ist implementierungsabhängig, da der C-Standard NICHT die Vorzeichen von char
definiert. Je nach Plattform kann char signed
oder unsigned
sein. Sie müssen daher explizit nach signed char
oder unsigned char
fragen, wenn Ihre Implementierung davon abhängt. Verwenden Sie einfach char
, wenn Sie Zeichen aus Zeichenfolgen darstellen möchten, da dies mit dem übereinstimmt, was Ihre Plattform in die Zeichenfolge einfügt.
Der Unterschied zwischen signed char
und unsigned char
ist wie erwartet. Auf den meisten Plattformen ist signed char
eine 8-Bit-Zweierkomplementzahl, die von -128
bis 127
reicht, und unsigned char
ist eine 8-Bit-Ganzzahl ohne Vorzeichen (0
bis 255
). Beachten Sie, dass der Standard NICHT erfordert, dass char
-Typen 8 Bits haben, sondern nur, dass sizeof(char)
1
zurückgibt. Sie können die Anzahl der Bits in einem Zeichen mit CHAR_BIT
in limits.h
ermitteln. Es gibt heutzutage nur wenige Plattformen, auf denen dies nicht nur 8
ist.
Es gibt eine nette Zusammenfassung dieser Ausgabe hier .
Wie andere bereits erwähnt haben, ist es besser, int8_t
und uint8_t
zu verwenden, wenn Sie wirklich kleine ganze Zahlen darstellen möchten.
Da ich der Meinung bin, dass es wirklich notwendig ist, möchte ich nur einige Regeln für C und C++ angeben (in dieser Hinsicht sind sie die gleichen). Zunächst nehmen alle Bits von unsigned char
an der Bestimmung des Werts eines vorzeichenlosen Zeichenobjekts teil. Zweitens wird unsigned char
ausdrücklich ohne Vorzeichen angegeben.
Jetzt hatte ich eine Diskussion mit jemandem darüber, was passiert, wenn Sie den Wert -1
vom Typ int in unsigned char
konvertieren. Er lehnte die Idee ab, dass das resultierende unsigned char
alle seine Bits auf 1 gesetzt hat, weil er sich Sorgen um die Darstellung von Vorzeichen machte. Muss er aber nicht. Aus dieser Regel folgt sofort, dass die Konvertierung das tut, was beabsichtigt ist:
Wenn der neue Typ kein Vorzeichen hat, wird der Wert konvertiert, indem wiederholt ein Wert mehr als der Maximalwert, der im neuen Typ dargestellt werden kann, addiert oder subtrahiert wird, bis der Wert im Bereich des neuen Typs liegt. (
6.3.1.3p2
in einem C99-Entwurf)
Das ist eine mathematische Beschreibung. C++ beschreibt es in Modulo-Berechnungen, die nach derselben Regel ablaufen. Auf jeden Fall ist nicht garantiert, dass alle Bits in der Ganzzahl -1
vor der Konvertierung eins sind. Was haben wir also, damit wir behaupten können, dass für den resultierenden unsigned char
alle CHAR_BIT
Bits auf 1 gesetzt sind?
UCHAR_MAX+1
zu -1
ergibt einen Wert im Bereich, nämlich UCHAR_MAX
.Das reicht eigentlich! Also, wann immer Sie einen unsigned char
haben möchten, der alle seine Bits eins hat, tun Sie dies
unsigned char c = (unsigned char)-1;
Daraus folgt auch, dass eine Konvertierung nicht nur höherwertige Bits abschneidet. Das glückliche Ereignis für Zweierkomplement ist, dass es dort nur eine Kürzung ist, aber dasselbe gilt nicht unbedingt für andere Zeichendarstellungen.
Wie zum Beispiel Verwendungen von nsigned char:
nsigned char wird häufig in Computergrafiken verwendet, bei denen (wenn auch nicht immer) jeder Farbkomponente ein einzelnes Byte zugewiesen wird. Es ist üblich, eine RGBoder RGBA-) Farbe als 24 (oder 32) Bits darzustellen, wobei jedes ein --- (vorzeichenloses Zeichen ist. Da vorzeichenlose Zeichen Werte im Bereich [0,255] liegen, werden die Werte normalerweise folgendermaßen interpretiert:
Sie erhalten also RGB-Rot als (255,0,0) -> (100% Rot, 0% Grün, 0% Blau).
Warum nicht ein signiertes Zeichen verwenden? Arithmetik und Bitverschiebung werden problematisch. Wie bereits erläutert, wird der Bereich von a vorzeichenbehaftetes Zeichen wesentlich um -128 verschoben. Eine sehr einfache und naive (meist nicht verwendete) Methode zur Konvertierung von RGB in Graustufen besteht darin, alle drei Farbkomponenten zu mitteln. Dies führt jedoch zu Problemen, wenn die Werte der Farbkomponenten negativ sind. Rot (255, 0, 0) ergibt einen Durchschnitt von (85, 85, 85), wenn vorzeichenloses Zeichen Arithmetik verwendet wird. Wenn die Werte jedoch vorzeichenbehaftetes Zeichen s (127, -128, -128) wären, erhalten wir (-99, -99, -99), was (29, 29, 29) in unserem nsigned char Raum, der falsch ist.
Wenn Sie ein Zeichen als kleine Ganzzahl verwenden möchten, ist dies am sichersten mit den Typen int8_t
und uint8_t
möglich.
unsigned char
nimmt nur positive Werte an .... wie bis 255
wohingegen
signed char
nimmt sowohl positive als auch negative Werte an .... wie - 128 bis + 127
char
und unsigned char
sind nicht auf allen Plattformen garantiert 8-Bit-Typen. Sie sind garantiert 8-Bit-Typen oder größer. Einige Plattformen haben 9-Bit-, 32-Bit- oder 64-Bit-Bytes . Die gängigsten Plattformen (Windows, Mac, Linux x86 usw.) haben jedoch 8-Bit-Bytes.
signed char
hat einen Bereich von -128 bis 127; unsigned char
hat einen Bereich von 0 bis 255.
char
entspricht je nach Compiler entweder dem Zeichen mit oder ohne Vorzeichen, ist jedoch ein anderer Typ.
Wenn Sie Zeichenfolgen im C-Stil verwenden, verwenden Sie einfach char
. Wenn Sie Zeichen für die Arithmetik verwenden müssen (ziemlich selten), geben Sie aus Gründen der Portabilität explizit signiert oder unsigniert an.
Ein vorzeichenloses Zeichen ist ein (vorzeichenloser) Bytewert (0 bis 255). Sie denken vielleicht, dass "char" ein "Charakter" ist, aber es ist wirklich ein numerischer Wert. Das reguläre "char" ist signiert, Sie haben also 128 Werte und diese Werte werden Zeichen mit der ASCII-Codierung zugeordnet. In beiden Fällen ist das, was Sie im Speicher speichern, ein Bytewert.
In Bezug auf direkte Werte wird ein reguläres Zeichen verwendet, wenn bekannt ist, dass die Werte zwischen CHAR_MIN
und CHAR_MAX
liegen, während ein vorzeichenloses Zeichen den doppelten Bereich am positiven Ende bereitstellt. Wenn CHAR_BIT
beispielsweise 8 ist, beträgt der Bereich für reguläres char
garantiert nur [0, 127] (da signiert oder nicht signiert sein kann), während unsigned char
[0] ist , 255] und signed char
sind [-127, 127].
In Bezug auf die Verwendungszwecke ermöglichen die Standards die direkte Konvertierung von POD-Objekten (Plain Old Data) in ein Array von Zeichen ohne Vorzeichen. Auf diese Weise können Sie die Darstellung und die Bitmuster des Objekts untersuchen. Die gleiche Garantie für sicheres Punning besteht nicht für char oder signed char.
Wenn Sie verschiedene Arten von Längen und Signaturen bevorzugen, sind Sie mit uint8_t, int8_t, uint16_t usw. wahrscheinlich besser dran, weil sie genau das tun, was sie sagen.
Ein vorzeichenloses Zeichen verwendet das Bit, das für das Vorzeichen eines regulären Zeichens reserviert ist, als eine andere Zahl. Dies ändert den Bereich auf [0 - 255] im Gegensatz zu [-128 - 127].
Im Allgemeinen werden Zeichen ohne Vorzeichen verwendet, wenn Sie kein Zeichen möchten. Dies macht einen Unterschied, wenn Sie z. B. Bits verschieben (Shift erweitert das Vorzeichen) und andere Dinge, wenn Sie ein Zeichen als Byte behandeln, anstatt es als Zahl zu verwenden.
zeichen ohne Vorzeichen ist das Herzstück aller kleinen Tricks. In fast ALL-Compiler für ALL-Plattform ist ein nicht signiertes Zeichen einfach ein BYTE. Eine vorzeichenlose ganze Zahl von (normalerweise) 8 Bit. das kann als eine kleine ganze Zahl oder ein Pack von Bits behandelt werden.
In der Sucht, wie jemand anderes gesagt hat, definiert der Standard nicht das Zeichen eines Zeichens. Sie haben also 3 verschiedene "char" -Typen: char, signed char, unsigned char.
Einige googeln fanden this , wo die Leute eine Diskussion darüber hatten.
Ein vorzeichenloses Zeichen ist im Grunde ein einzelnes Byte. Sie würden dies also verwenden, wenn Sie ein Datenbyte benötigen (z. B. möchten Sie damit Flags aktivieren oder deaktivieren, die an eine Funktion übergeben werden sollen, wie dies in der Windows-API häufig der Fall ist).
zeichen ohne Vorzeichen nehmen nur positive Werte an: 0 bis 255 Zeichen mit Vorzeichen nehmen positive und negative Werte an: -128 bis +127
zitat aus dem Buch "the c programming laugage":
Das Qualifikationsmerkmal signed
oder unsigned
kann auf char oder eine beliebige Ganzzahl angewendet werden. vorzeichenlose Zahlen sind immer positiv oder null und befolgen die Gesetze des arithmetischen Moduls 2 ^ n, wobei n die Anzahl der Bits im Typ ist. Wenn Zeichen beispielsweise 8 Bit lang sind, haben vorzeichenlose Zeichenvariablen Werte zwischen 0 und 255, während vorzeichenbehaftete Zeichen Werte zwischen -128 und 127 haben (auf einem Zweierkomplement-Computer) -abhängige, aber druckbare Zeichen sind immer positiv.