Sollte ein Puffer von Bytes ein Zeichen mit Vorzeichen oder ein Zeichen ohne Vorzeichen oder einfach ein Zeichenpuffer sein? Irgendwelche Unterschiede zwischen C und C++?
Vielen Dank.
Sollte ein Puffer von Bytes ein Zeichen mit Vorzeichen oder ein Zeichen ohne Vorzeichen oder einfach ein Zeichenpuffer sein? Irgendwelche Unterschiede zwischen C und C++?
Vielen Dank.
Johannes Schaub – litb
Wenn Sie beabsichtigen, beliebige Binärdaten zu speichern, sollten Sie verwenden unsigned char
. Es ist der einzige Datentyp, der vom C-Standard garantiert keine Füllbits enthält. Jeder andere Datentyp kann Füllbits in seiner Objektdarstellung enthalten (also diejenige, die alle Bits eines Objekts enthält, anstatt nur die, die einen Wert bestimmen). Der Zustand der Füllbits ist nicht spezifiziert und wird nicht zum Speichern von Werten verwendet. Also, wenn Sie mit lesen char
Bei einigen Binärdaten würden die Dinge auf den Wertebereich eines Zeichens reduziert (indem nur die Wertbits interpretiert werden), aber es kann immer noch Bits geben, die einfach ignoriert werden, aber dennoch vorhanden sind und gelesen werden memcpy
. Ähnlich wie Füllbits in echten Strukturobjekten. Typ unsigned char
enthält diese garantiert nicht. Das folgt aus 5.2.4.2.1/2
(C99 TC2, n1124 hier):
Wenn der Wert eines Objekts vom Typ char bei Verwendung in einem Ausdruck als Ganzzahl mit Vorzeichen behandelt wird, wird der Wert von
CHAR_MIN
soll die gleiche sein wie die vonSCHAR_MIN
und der Wert vonCHAR_MAX
soll die gleiche sein wie die vonSCHAR_MAX
. Andernfalls ist der Wert von
CHAR_MIN
soll 0 und der Wert von seinCHAR_MAX
soll die gleiche sein wie die von
UCHAR_MAX
. Der WertUCHAR_MAX
soll gleich sein2^CHAR_BIT − 1
Aus dem letzten Satz folgt, dass kein Platz mehr für Füllbits bleibt. Wenn du benutzt char
Als Typ Ihres Puffers haben Sie auch das Problem von Überläufen: Weisen Sie einem solchen Element, das im Bereich von liegt, einen beliebigen Wert explizit zu 8
Bits – Sie können also davon ausgehen, dass eine solche Zuordnung in Ordnung ist – aber nicht im Bereich von a char
welches ist CHAR_MIN
..CHAR_MAX
so läuft eine solche Konvertierung über und verursacht implementierungsdefinierte Ergebnisse, einschließlich der Signalerhöhung.
Auch wenn Probleme in Bezug auf das oben Gesagte wahrscheinlich nicht in realen Implementierungen auftreten würden (wäre a sehr schlechte Qualität der Implementierung), verwenden Sie am besten von Anfang an den richtigen Typ, nämlich unsigned char
.
Für Strings ist jedoch der Datentyp der Wahl char
, die von String- und Druckfunktionen verstanden wird. Verwenden signed char
für diese Zwecke sieht für mich nach einer Fehlentscheidung aus.
Weitere Informationen finden Sie unter this proposal
die einen Fix für eine nächste Version des C-Standards enthalten, die eventuell benötigt wird signed char
haben auch keine Füllbits. Es ist bereits in die integriert Arbeitspapier.
B-aber C99 6.2.6.2 sagt “signed char darf keine Füllbits haben”
– StaceyGirl
17. Januar 2014 um 1:16 Uhr
Vergiss C. [C++11: 3.9.1/1]:
[..] Ein Zeichen, ein Zeichen mit Vorzeichen und ein Zeichen ohne Vorzeichen belegen die gleiche Menge an Speicherplatz und haben die gleichen Ausrichtungsanforderungen (3.11); das heißt, sie haben dieselbe Objektdarstellung. Bei Zeichentypen nehmen alle Bits der Objektdarstellung an der Wertdarstellung teil. [..] Deutet das nicht darauf hin alle drei Charaktertypen haben zumindest die gleich Polsterung? Und ich interpretiere es weiter so, dass keiner von ihnen welche hat.
– Leichtigkeitsrennen im Orbit
17. Januar 2014 um 1:32 Uhr
uintN_t
und intN_t
haben auch keine Füllbytes.
– 12431234123412341234123
25. April 2017 um 7:37 Uhr
Sollte ein Puffer von Bytes ein Zeichen mit Vorzeichen oder ein Zeichen ohne Vorzeichen oder einfach ein Zeichenpuffer sein? Irgendwelche Unterschiede zwischen C und C++?
Ein kleiner Unterschied, wie die Sprache damit umgeht. EIN riesig Unterschied, wie die Konvention damit umgeht.
char
= ASCII (oder UTF-8, aber die Vorzeichen stehen dort im Weg) textlich Datenunsigned char
= Bytesigned char
= selten verwendetUnd es gibt Code dafür beruht auf eine solche Unterscheidung. Erst vor ein oder zwei Wochen stieß ich auf einen Fehler, bei dem JPEG-Daten beschädigt wurden, weil sie an die weitergegeben wurden char*
Version unserer Base64-Kodierungsfunktion – die „hilfreich“ alle ungültigen UTF-8 in der „Zeichenfolge“ ersetzte. Wechseln zu BYTE
auch bekannt unsigned char
war alles, was es brauchte, um es zu reparieren.
Warum also verwenden die C++-Iostreams char*
Anstatt von unsigned char*
zur Darstellung von Datenpuffern beim Lesen und Schreiben von Binärströmen read
und write
Methoden? 😛
– BarbaraKwarc
13. Januar 2017 um 11:06 Uhr
signed char ist gar nicht so selten. In JNI (java native interface, NDK 14.1) ist signed char als jbyte definiert.
– r0n9
7. April 2017 um 0:45 Uhr
wtf hat java damit zu tun (ugh)
– Entwicklerbmw
17. September 2017 um 8:05 Uhr
@developerbmw: Herr Gosling [inventor of Java] sah all die Schwierigkeiten, die durch vorzeichenlose Typen verursacht wurden, die nicht zu einem vorzeichenbehafteten Integer-Typ befördert wurden, und entschied daher, dass Java dies nicht tun sollte irgendein unsignierte Typen (außer – aus irgendeinem Grund –char
), anstatt zu sagen – wie es einige andere Sprachen wie Pascal getan hatten – dass die einzigen vorzeichenlosen Typen diejenigen sein sollten, die zu einem vorzeichenbehafteten Integer-Typ werden würden.
– Superkatze
13. Juli 2018 um 16:00 Uhr
Es hängt davon ab, ob.
Wenn der Puffer Text enthalten soll, ist es wahrscheinlich sinnvoll, ihn als Array von zu deklarieren char
und lassen Sie die Plattform für Sie entscheiden, ob dies standardmäßig signiert oder unsigniert ist. Dadurch haben Sie beispielsweise die geringsten Probleme, die Daten in die und aus der Laufzeitbibliothek der Implementierung zu übergeben.
Wenn der Puffer Binärdaten enthalten soll, hängt dies davon ab, wie Sie ihn verwenden möchten. Wenn zum Beispiel die Binärdaten wirklich ein gepacktes Array von Datenabtastwerten sind, die 8-Bit-Festkomma-ADC-Messungen sind, dann signed char
wäre am besten.
In den meisten realen Fällen ist der Puffer genau das, ein Puffer, und Sie kümmern sich nicht wirklich um die Typen der einzelnen Bytes, weil Sie den Puffer in einer Massenoperation gefüllt haben und ihn gleich an a übergeben möchten Parser, um die komplexe Datenstruktur zu interpretieren und etwas Nützliches zu tun. Deklarieren Sie es in diesem Fall auf einfachste Weise.
Wenn es sich tatsächlich um einen Puffer mit 8-Bit-Bytes handelt und nicht um eine Zeichenfolge im Standardgebietsschema des Computers, würde ich verwenden uint8_t
. Nicht, dass es viele Maschinen gibt, auf denen ein Zeichen kein Byte (oder ein Byte ein Oktett) ist, aber die Aussage „Dies ist ein Puffer von Oktetten“ anstelle von „Dies ist eine Zeichenfolge“ ist oft eine nützliche Dokumentation.
Sie sollten beides verwenden verkohlen oder unsigned char aber nie unterschriebenes Zeichen. Der Standard hat folgendes in 3.9/2
Für jedes Objekt (außer einem Unterobjekt der Basisklasse) des POD-Typs T, unabhängig davon, ob das Objekt einen gültigen Wert des Typs T enthält oder nicht, können die zugrunde liegenden Bytes (1.7), aus denen das Objekt besteht, in ein Array von char oder unsigned kopiert werden char. Wenn der Inhalt des Arrays von char oder unsigned char zurück in das Objekt kopiert wird, soll das Objekt anschließend seinen ursprünglichen Wert behalten.
Naveen
Es ist besser, es als unsigned char zu definieren. Tatsächlich ist der Win32-Typ BYTE als unsigned char definiert. Es gibt keinen Unterschied zwischen C und C++.
MrEvil
Verwenden Sie für maximale Portabilität immer unsigned char. Es gibt ein paar Fälle, in denen dies ins Spiel kommen könnte. Serialisierte Daten, die über Systeme mit unterschiedlichem Endian-Typ geteilt werden, fallen sofort ein. Beim Durchführen von Verschiebung oder Bitmaskierung sind die Werte andere.
Dupe mit stackoverflow.com/questions/13819820
– Kebs
24. Januar 2018 um 15:18 Uhr