Was ist der Vorteil der Verwendung uint8_t
Über unsigned char
in C?
Das kenne ich von fast jedem System uint8_t
ist nur eine Typdefinition für unsigned char
warum also verwenden?
Rahmen Catherine White
Was ist der Vorteil der Verwendung uint8_t
Über unsigned char
in C?
Das kenne ich von fast jedem System uint8_t
ist nur eine Typdefinition für unsigned char
warum also verwenden?
Mark Lösegeld
Es dokumentiert Ihre Absicht – Sie speichern eher kleine Zahlen als ein Zeichen.
Es sieht auch schöner aus, wenn Sie andere Typedefs verwenden, wie z uint16_t
oder int32_t
.
Explizit verwenden unsigned char
oder signed char
dokumentiert die Absicht auch, da ungeschminkt char
zeigt, dass Sie mit Charakteren arbeiten.
– Café
12. November 2009 um 23:37 Uhr
Ich dachte, eine schmucklose unsigned
war unsigned int
per Definition?
– Markieren Sie Lösegeld
29. November 2009 um 19:29 Uhr
@endolith, die Verwendung von uint8_t für eine Zeichenfolge ist nicht unbedingt falsch, aber definitiv seltsam.
– Markieren Sie Lösegeld
14. November 2011 um 13:58 Uhr
@endolith, ich denke, ich kann mit UTF8-Text für uint8_t plädieren. In der Tat, char
scheint ein Zeichen zu implizieren, während es im Kontext einer UTF8-Zeichenfolge nur ein Byte eines Multibyte-Zeichens sein kann. Die Verwendung von uint8_t könnte deutlich machen, dass man nicht an jeder Position ein Zeichen erwarten sollte – mit anderen Worten, dass jedes Element des Strings/Arrays eine beliebige Ganzzahl ist, über die man keine semantischen Annahmen treffen sollte. Natürlich wissen das alle C-Programmierer, aber es kann Anfänger dazu bringen, die richtigen Fragen zu stellen.
– tne
16. Januar 2014 um 11:46 Uhr
Ich muss sagen, unsigned char
wird nicht wirklich zum Speichern von Zeichen verwendet, daher ist das Problem der “Absicht” strittig.
– Benutzer541686
22. Juli 2014 um 11:00 Uhr
Chris Lutz
Nur um pedantisch zu sein, einige Systeme haben möglicherweise keinen 8-Bit-Typ. Entsprechend Wikipedia:
Eine Implementierung ist erforderlich, um ganzzahlige Typen mit exakter Breite für N = 8, 16, 32 oder 64 zu definieren, wenn und nur wenn sie einen Typ hat, der die Anforderungen erfüllt. Es ist nicht erforderlich, sie für jedes andere N zu definieren, selbst wenn es die entsprechenden Typen unterstützt.
So uint8_t
Es ist nicht garantiert, dass es existiert, obwohl es für alle Plattformen existiert, auf denen 8 Bits = 1 Byte sind. Einige eingebettete Plattformen mögen anders sein, aber das wird sehr selten. Einige Systeme können definieren char
16-Bit-Typen, in diesem Fall wird es wahrscheinlich keinen 8-Bit-Typ geben.
Abgesehen von diesem (kleinen) Problem ist die Antwort von @ Mark Ransom meiner Meinung nach die beste. Verwenden Sie diejenige, die am deutlichsten zeigt, wofür Sie die Daten verwenden.
Außerdem gehe ich davon aus, dass du gemeint hast uint8_t
(die Standard-Typedef von C99, die in der stdint.h
Kopfzeile) statt uint_8
(nicht Teil einer Norm).
@caf, aus reiner Neugier – können Sie auf die Beschreibung einiger verlinken? Ich weiß, dass sie existieren, weil jemand in einer comp.lang.c++.moderierten Diskussion darüber, ob C/C++-Typgarantien zu schwach sind, einen erwähnt (und mit Entwicklerdokumenten dafür verlinkt), aber ich kann diesen Thread nicht mehr finden, und er ist immer praktisch um in ähnlichen Diskussionen darauf hinzuweisen 🙂
– Pavel Minaev
12. November 2009 um 23:40 Uhr
“Einige Systeme können Zeichentypen mit 16 Bit definieren, in diesem Fall wird es wahrscheinlich keinen 8-Bit-Typ geben.” – und trotz einiger falscher Einwände von mir hat Pavel in seiner Antwort gezeigt, dass, wenn char 16 Bit ist, der Compiler selbst dann einen 8-Bit-Typ bereitstellt darf nicht nennen uint8_t
(oder typedef es dazu). Dies liegt daran, dass der 8-Bit-Typ ungenutzte Bits in der Speicherdarstellung hätte, was uint8_t
darf nicht haben.
– Steve Jessop
13. November 2009 um 3:29 Uhr
Die SHARC-Architektur hat 32-Bit-Wörter. Sehen de.wikipedia.org/wiki/… für Details.
– BCran
13. November 2009 um 16:17 Uhr
Und die C5000-DSPs von TI (die in OMAP1 und OMAP2 enthalten waren) sind 16-Bit. Ich denke, für OMAP3 gingen sie zur C6000-Serie mit einem 8-Bit-Zeichen.
– Steve Jessop
13. November 2009 um 17:30 Uhr
Graben in N3242 – “Working Draft, Standard for Programming Language C++”, Abschnitt 18.4.1 < cstdint > synopsis sagt – typedef unsigned integer type uint8_t; // optional
Im Wesentlichen wird also keine dem C++-Standard entsprechende Bibliothek benötigt, um uint8_t überhaupt zu definieren (siehe Kommentar //optional).
– nächtliche Wanderwege
23. Februar 2013 um 9:17 Uhr
AnT steht zu Russland
Der springende Punkt ist, implementierungsunabhängigen Code zu schreiben. unsigned char
ist nicht garantiert ein 8-Bit-Typ. uint8_t
ist (falls vorhanden).
…wenn es auf einem System existiert, aber das wird sehr selten sein. +1
– Chris Lutz
12. November 2009 um 22:57 Uhr
Nun, wenn Sie wirklich Probleme damit hatten, dass Ihr Code auf einem System nicht kompiliert wurde, weil uint8_t nicht existierte, könnten Sie find und sed verwenden, um alle Vorkommen von uint8_t automatisch in unsigned char oder etwas Nützlicheres für Sie zu ändern.
– Buzz
24. Juli 2014 um 20:36 Uhr
@bazz – nicht, wenn Sie davon ausgehen, dass es sich um einen 8-Bit-Typ handelt, den Sie nicht können – zum Beispiel, um Daten zu entpacken, die von einem Remote-System byteweise gepackt wurden. Die implizite Annahme ist, dass der Grund dafür, dass uint8_t nicht vorhanden ist, auf einem Prozessor liegt, auf dem ein Zeichen mehr als 8 Bit lang ist.
– Chris Stratton
11. April 2015 um 21:56 Uhr
Assertion einwerfen (sizeof(unsigned char) == 8);
– Buzz
12. April 2015 um 22:29 Uhr
@bazz falsche Behauptung, fürchte ich. sizeof(unsigned char)
wird zurückkehren 1
für 1Byte. aber wenn ein System char und int die gleiche Größe von zB 16-Bit haben, dann sizeof(int)
wird auch wiederkommen 1
– Tobi
29. Mai 2015 um 9:22 Uhr
Nur verliebt
Wie du gesagt hast, “fast jedes System”.
char
ist wahrscheinlich einer der weniger wahrscheinlich zu ändern, aber sobald Sie mit der Verwendung beginnen uint16_t
und Freunde, mit uint8_t
mischt sich besser und kann sogar Teil eines Codierungsstandards sein.
Es gibt wenig. Aus Sicht der Portabilität char
kann nicht kleiner als 8 Bit sein, und nichts kann kleiner sein als char
wenn also eine bestimmte C-Implementierung einen vorzeichenlosen 8-Bit-Ganzzahltyp hat, wird es so sein char
. Alternativ kann es sein, dass es gar keins hat, an welchem Punkt eines typedef
Tricks sind umstritten.
Es könnte verwendet werden, um Ihren Code in dem Sinne besser zu dokumentieren, dass klar ist, dass Sie dort 8-Bit-Bytes benötigen und sonst nichts. Aber in der Praxis ist es praktisch überall schon eine vernünftige Erwartung (es gibt DSP-Plattformen, auf denen es nicht zutrifft, aber die Chancen, dass Ihr Code dort läuft, sind gering, und Sie könnten genauso gut einen Fehler machen, indem Sie eine statische Bestätigung oben in Ihrem Programm verwenden eine solche Plattform).
Fürs Protokoll: Sie könnten auf jeder Plattform einen 8-Bit-Typ erstellen: typedef struct { unsigned i :8; } uint8_t;
aber Sie müssten es als verwenden uint8_t x; x.i = ...
also etwas umständlicher.
– Chris Lutz
12. November 2009 um 22:45 Uhr
@Skizz – Nein, der Standard erfordert unsigned char
Werte zwischen 0 und 255 halten zu können. Wenn du das in 4 Bit schaffst, dann ziehe ich den Hut.
– Chris Lutz
12. November 2009 um 22:50 Uhr
“es wäre ein bisschen umständlicher” – umständlich in dem Sinne, dass Sie den ganzen Weg dorthin laufen (schwimmen, ein Flugzeug nehmen usw.) müssten, wo der Compiler-Autor war, und ihm auf den Hinterkopf schlagen , und lassen Sie sie hinzufügen uint8_t
zur Umsetzung. Ich frage mich, ob Compiler für DSPs normalerweise 16-Bit-Zeichen implementieren uint8_t
oder nicht?
– Steve Jessop
12. November 2009 um 23:06 Uhr
Übrigens, bei näherer Überlegung ist es vielleicht die einfachste Art zu sagen “Ich brauche wirklich 8 Bit” – #include <stdint.h>
und verwenden uint8_t
. Wenn die Plattform es hat, wird es Ihnen gegeben. Wenn die Plattform es nicht hat, wird Ihr Programm nicht kompiliert, und der Grund wird klar und einfach sein.
– Pavel Minaev
12. November 2009 um 23:23 Uhr
Immer noch keine Zigarre, sorry: “Für unsigned Integer-Typen außer unsigned char müssen die Bits der Objektdarstellung in zwei Gruppen unterteilt werden: Wertbits und Füllbits … Wenn es N Wertbits gibt, soll jedes Bit ein anderes darstellen Potenz von 2 zwischen 1 und 2^(N-1), sodass Objekte dieses Typs in der Lage sein sollen, Werte von 0 bis 2^(N-1) unter Verwendung einer reinen binären Darstellung darzustellen … Der Typedef-Name intN_t bezeichnet a vorzeichenbehafteter ganzzahliger Typ mit Breite N, keine Füllbitsund eine Zweierkomplementdarstellung.”
– Pavel Minaev
13. November 2009 um 2:38 Uhr
Gemeinschaft
Meiner Erfahrung nach gibt es zwei Stellen, an denen wir uint8_t verwenden möchten, um 8 Bit (und uint16_t usw.) zu bedeuten, und an denen wir Felder haben können, die kleiner als 8 Bit sind. An beiden Stellen kommt es auf Platz an, und wir müssen uns beim Debuggen oft einen Rohdatenauszug der Daten ansehen und schnell feststellen können, was er darstellt.
Der erste liegt in HF-Protokollen, insbesondere in Schmalbandsystemen. In dieser Umgebung müssen wir möglicherweise so viele Informationen wie möglich in eine einzige Nachricht packen. Der zweite ist der Flash-Speicher, wo wir möglicherweise sehr begrenzten Platz haben (z. B. in eingebetteten Systemen). In beiden Fällen können wir eine gepackte Datenstruktur verwenden, bei der der Compiler das Packen und Entpacken für uns übernimmt:
#pragma pack(1)
typedef struct {
uint8_t flag1:1;
uint8_t flag2:1;
padding1 reserved:6; /* not necessary but makes this struct more readable */
uint32_t sequence_no;
uint8_t data[8];
uint32_t crc32;
} s_mypacket __attribute__((packed));
#pragma pack()
Welche Methode Sie verwenden, hängt von Ihrem Compiler ab. Möglicherweise müssen Sie auch mehrere verschiedene Compiler mit denselben Header-Dateien unterstützen. Dies geschieht in eingebetteten Systemen, in denen Geräte und Server völlig unterschiedlich sein können – beispielsweise haben Sie möglicherweise ein ARM-Gerät, das mit einem x86-Linux-Server kommuniziert.
Es gibt ein paar Vorbehalte bei der Verwendung von gepackten Strukturen. Das größte Problem ist, dass Sie vermeiden müssen, die Adresse eines Mitglieds zu dereferenzieren. Auf Systemen mit Multibyte-ausgerichteten Wörtern kann dies zu einer falsch ausgerichteten Ausnahme und einem Arbeitsspeicherabzug führen.
Einige Leute werden sich auch Sorgen um die Leistung machen und argumentieren, dass die Verwendung dieser gepackten Strukturen Ihr System verlangsamen wird. Es stimmt, dass der Compiler hinter den Kulissen Code hinzufügt, um auf die nicht ausgerichteten Datenelemente zuzugreifen. Sie können das sehen, indem Sie sich den Assembler-Code in Ihrer IDE ansehen.
Aber da gepackte Strukturen für die Kommunikation und Datenspeicherung am nützlichsten sind, können die Daten in eine nicht gepackte Darstellung extrahiert werden, wenn man damit im Speicher arbeitet. Normalerweise müssen wir sowieso nicht mit dem gesamten Datenpaket im Speicher arbeiten.
Hier ist eine relevante Diskussion:
pragma pack(1) noch __attribute__ ((aligned (1))) funktioniert
Ist das __attribute__((packed))/#pragma pack von gcc unsicher?
http://solidsmoke.blogspot.ca/2010/07/woes-of-structure-packing-pragma-pack.html
Fürs Protokoll: Sie könnten auf jeder Plattform einen 8-Bit-Typ erstellen: typedef struct { unsigned i :8; } uint8_t;
aber Sie müssten es als verwenden uint8_t x; x.i = ...
also etwas umständlicher.
– Chris Lutz
12. November 2009 um 22:45 Uhr
@Skizz – Nein, der Standard erfordert unsigned char
Werte zwischen 0 und 255 halten zu können. Wenn du das in 4 Bit schaffst, dann ziehe ich den Hut.
– Chris Lutz
12. November 2009 um 22:50 Uhr
“es wäre ein bisschen umständlicher” – umständlich in dem Sinne, dass Sie den ganzen Weg dorthin laufen (schwimmen, ein Flugzeug nehmen usw.) müssten, wo der Compiler-Autor war, und ihm auf den Hinterkopf schlagen , und lassen Sie sie hinzufügen uint8_t
zur Umsetzung. Ich frage mich, ob Compiler für DSPs normalerweise 16-Bit-Zeichen implementieren uint8_t
oder nicht?
– Steve Jessop
12. November 2009 um 23:06 Uhr
Übrigens, bei näherer Überlegung ist es vielleicht die einfachste Art zu sagen “Ich brauche wirklich 8 Bit” – #include <stdint.h>
und verwenden uint8_t
. Wenn die Plattform es hat, wird es Ihnen gegeben. Wenn die Plattform es nicht hat, wird Ihr Programm nicht kompiliert, und der Grund wird klar und einfach sein.
– Pavel Minaev
12. November 2009 um 23:23 Uhr
Immer noch keine Zigarre, sorry: “Für unsigned Integer-Typen außer unsigned char müssen die Bits der Objektdarstellung in zwei Gruppen unterteilt werden: Wertbits und Füllbits … Wenn es N Wertbits gibt, soll jedes Bit ein anderes darstellen Potenz von 2 zwischen 1 und 2^(N-1), sodass Objekte dieses Typs in der Lage sein sollen, Werte von 0 bis 2^(N-1) unter Verwendung einer reinen binären Darstellung darzustellen … Der Typedef-Name intN_t bezeichnet a vorzeichenbehafteter ganzzahliger Typ mit Breite N, keine Füllbitsund eine Zweierkomplementdarstellung.”
– Pavel Minaev
13. November 2009 um 2:38 Uhr
VP.
Das ist zum Beispiel wirklich wichtig, wenn Sie einen Netzwerkanalysator schreiben. Paket-Header werden durch die Protokollspezifikation definiert, nicht durch die Funktionsweise des C-Compilers einer bestimmten Plattform.
Damals, als ich das fragte, war ich definitiv ein einfaches Protokoll für die Kommunikation über die serielle Schnittstelle.
– Frames Catherine White
4. Juni 2011 um 11:47 Uhr