Sollte ein Puffer von Bytes mit oder ohne Vorzeichen char buffer werden?
Frage
Wenn ein Puffer von Bytes char oder unsigned char oder einfach einen char buffer unterzeichnet werden? Unterschiede zwischen C und C ++?
Danke.
Lösung
Wenn ein Puffer von Bytes zu unterzeichnen char oder unsigned char oder einfach ein char Puffer, Prellbock, Dämpfer? Unterschiede zwischen C und C ++?
Ein kleiner Unterschied, wie die Sprache, es behandelt. Ein großen Unterschied, wie Konvention behandelt es.
-
char
= ASCII (oder UTF-8, aber die Signedness in die Quere kommt es) Text Daten -
unsigned char
= Byte -
signed char
= selten verwendet
Und es ist Code, der setzt auf eine solche Unterscheidung. Nur eine Woche oder zwei Jahren traf ich einen Fehler in dem JPEG-Daten wurden beschädigt zu werden, da es wurde auf die char*
Version unserer Base64 kodieren Funktion übergeben werden - die „helfend“ alle ungültigen UTF-8 ersetzt in der „string“. Ändern aka BYTE
unsigned char
war alles, es dauerte es zu beheben.
Andere Tipps
Wenn Sie beabsichtigen, beliebige binäre Daten zu speichern, sollten Sie unsigned char
verwenden. Es ist der einzige Datentyp, der keine Füllbits von C-Standard haben, gewährleistet ist. Jeder anderer Datentyp kann Füllbits in ihrer Objektdarstellung enthält (das ist derjenige, der alle Bits eines Objekts enthält, und nicht nur diejenigen, die einen Wert bestimmt). Die Füllbits Zustand ist nicht näher bezeichnet sind und nicht zum Speichern von Werten verwendet. Also, wenn Sie einige binäre Daten mit char
lesen, würde die Dinge geschnitten werden bis auf den Wertebereich eines char (indem nur die Wert-Bits zu interpretieren), aber es gibt noch Bits sein kann, die einfach ignoriert werden, aber immer noch da sind und von memcpy
lesen. Ähnlich wie Füllbits in Echt struct Objekte. Typ unsigned char
garantiert diejenigen, die nicht enthalten. Das ergibt sich aus 5.2.4.2.1/2
(C99 TC2, n1124 hier):
Wenn der Wert von einem Objekt vom Typ char wird als vorzeichenbehaftete ganze Zahl behandelt, wenn sie in einem verwendet Ausdruck wird der Wert von
CHAR_MIN
das gleiche sein wie die desSCHAR_MIN
und dem Wert vonCHAR_MAX
ist das gleiche wie die vonSCHAR_MAX
sein. Andernfalls wird der Wert vonCHAR_MIN
soll 0 sein und der Wert vonCHAR_MAX
soll das gleiche sein wie die derUCHAR_MAX
. Der WertUCHAR_MAX
wird gleich2^CHAR_BIT − 1
Aus dem letzten Satz folgt, dass es keinen Raum für irgendwelche Paddingbits links ist. Wenn Sie char
als Typ Ihres Puffer zu verwenden, müssen Sie auch das Problem der Überläufe: einen beliebigen Wert zuweisen explizit auf ein solches Element, das im Bereich von 8
Bits ist - so können Sie eine solche Zuordnung erwarten in Ordnung zu sein - aber nicht innerhalb der Bereich eines char
, die CHAR_MIN
..CHAR_MAX
, eine solche Umwandlung überläuft und bewirkt, dass die Umsetzung definiert Ergebnisse, einschließlich der Erhöhung von Signalen.
Auch wenn irgendwelche Probleme der oben in Bezug auf würden wahrscheinlich in realen Implementierungen zeigen nicht (wäre ein sehr schlechte Qualität der Implementierung), Sie sind am besten die richtige Art von Anfang an ab, verwenden, das ist unsigned char
.
Bei Strings der Datentyp der Wahl ist jedoch char
, die durch Streich- und Druckfunktionen verstanden wird. Mit signed char
für diese Zwecke sieht aus wie eine falsche Entscheidung für mich.
Für weitere Informationen lesen Sie this proposal
die enthalten ein Update für eine nächste Version des C-Standard, die schließlich erfordern signed char
keine Füllbits haben entweder. Es ist bereits in die rel="noreferrer">.
Es hängt davon ab.
Wenn der Puffer Text halten soll, dann ist es wahrscheinlich sinnvoll, es als ein Array von char
zu erklären, und lassen Sie die Plattform für Sie entscheiden, ob die Unterzeichnung oder standardmäßig nicht signiert. Das gibt Ihnen die geringste Mühe Führen der Daten in die und aus der Laufzeitbibliothek Implementierung, zum Beispiel.
Wenn der Puffer soll binäre Daten halten, dann hängt es davon ab, wie Sie beabsichtigen, es zu benutzen. Wenn beispielsweise die binären Daten wirklich eine gepackte Anordnung von Datenproben, die 8-Bit-Festpunkt ADC Messungen unterzeichnet werden, dann wäre signed char
am besten.
In den meisten realen Fällen ist der Puffer nur, dass ein Puffer, und Sie nicht wirklich über die Art des einzelnen Bytes, weil Sie den Puffer in einem Massenvorgang gefüllt, und Sie sind dabei, es zu passieren aus, um einen Parser die komplexe Datenstruktur und etwas Sinnvolles tun zu interpretieren. In diesem Fall meldet es auf einfachste Art und Weise.
Wenn es tatsächlich ein Puffer von 8-Bit-Bytes, anstatt eine Zeichenfolge in dem Standardgebietsschema der Maschine, dann würde ich uint8_t
verwenden. Nicht, dass es viele Maschinen um, wo ein Zeichen ist kein Byte (oder ein Byte ein Oktett), aber macht die Aussage ‚das ist ein Puffer von Bytes‘ und nicht ‚dies ist ein String‘ wird oft nützliche Dokumentation.
Sie sollten entweder char oder unsigned char und nie signed char . Der Standard hat folgende in 3,9 / 2
Für jedes Objekt (andere als ein Basisklasse Subobjekt) des POD-Typ T, ob oder nicht hält das Objekt ein gültige Wert vom Typ T, die darunter liegenden Bytes (1.7) kann das Objekt bilden, kopiert werden, in eine Anordnung von char oder unsigned char.If der Gehalt an das Array von char oder unsigned char ist zurück in das Objekt kopiert, die Objekt wird anschließend halten ihre ursprünglicher Wert.
Es ist besser, es als unsigned char zu definieren. Infact Win32 Typ Byte als unsigned char definiert. Es gibt keinen Unterschied zwischen C & C ++ zwischen diesen.
Für maximale Portabilität verwenden immer unsigned char. Es gibt ein paar Fälle, in denen dies ins Spiel kommen könnte. Serialisierten Daten zwischen Systemen mit unterschiedlichen Endian-Typ geteilt kommt sofort in den Sinn. Beim Durchführen Verschiebung oder Bit der Werte Maskieren ist eine andere.
Die Wahl der int8_t vs uint8_t ist ähnlich, wenn Sie eine ptr sein NULL vergleichen.
Von einer Funktionalität Sicht auf NULL zu vergleichen ist das gleiche wie im Vergleich zu 0, weil NULL ein #define für 0 ist.
Aber persönlich von einem Codierungsstil Sicht, wähle ich meine Zeiger auf NULL zu vergleichen, weil die NULL #define an der Person konnotiert den Code beibehalten, die Sie für einen schlechten Zeiger werden überprüft ...
VS
, wenn jemand einen Vergleich zu 0 sieht es konnotiert, dass Sie für einen bestimmten Wert prüft wird.
Aus dem obigen Grunde würde ich verwenden uint8_t.
Wenn Sie ein Element in einen größeren Variable holen, wird es natürlich sein vorzeichenerweiterte oder nicht.
sollte und ... Ich neige dazu, bevorzugen nicht unterzeichnet, da es fühlt sich mehr „raw“, weniger einladend zu sagen: „Hey, das ist nur ein Haufen von kleinen ints
“, wenn ich will betont die binär-ness der Daten.
Ich glaube nicht, dass ich jemals eine explizite signed char
einen Puffer von Bytes darstellen verwendet.
Natürlich ist eine dritte Möglichkeit ist, den Puffer als void *
so viel wie möglich zu vertreten. Viele gängige E / A-Funktionen arbeiten mit void *
, so dass manchmal die Entscheidung, was Integer-Typ kann verwendet werden vollständig gekapselt werden, was schön ist.
Vor einigen Jahren hatte ich ein Problem mit einer C ++ Konsolenanwendung, die farbigen Zeichen für ASCII-Werte über 128 gedruckt und wurde dieses Problem gelöst, indem von char unsigned char wechseln, aber ich denke, es lösbar gewesen war, während char-Typen zu halten, auch.
Für jetzt, die meisten C / C ++ Funktionen char und ich verstehe beiden Sprachen jetzt viel besser, so dass ich char in den meisten Fällen.
Kümmern Sie wirklich? Wenn Sie dies nicht tun, verwenden Sie einfach den Standard (char) und keine Unordnung Ihren Code nicht mit unwichtiger Angelegenheit. Andernfalls wird künftig Maintainer sich fragen, warum verlassen Sie (oder ohne Vorzeichen), verwenden Sie unterzeichnet haben. Machen Sie ihr Leben einfacher.
Wenn Sie an den Compiler liegen, wird es Sie bestrafen.
Wenn der Puffer enthält Daten, die gerade durchlaufen, und Sie werden sie nicht in irgendeiner Weise manipulieren, spielt es keine Rolle.
Wenn Sie jedoch auf den Pufferinhalt arbeiten müssen dann die richtige Typdeklaration wird Ihr Code einfacher. No "int val = buf [i] & 0xff;" Unsinn.
Also, darüber nachzudenken, was die Daten tatsächlich ist und wie Sie es verwenden müssen.
typedef char byte;
Jetzt können Sie Ihr Array machen von byte
s sein. Es ist für jeden offensichtlich, was Sie meinen, und Sie verlieren keine Funktionalität.
Ich weiß, dass es etwas albern, aber es macht den Code lesen 100%, wie Sie beabsichtigten.