Was ist der Vorteil der Verwendung von uint8_t
mehr als unsigned char
in C?
Ich weiß, dass auf fast jedem System uint8_t
nur ein Typedef für ist unsigned char
, warum also verwenden?
Was ist der Vorteil der Verwendung von uint8_t
mehr als unsigned char
in C?
Ich weiß, dass auf fast jedem System uint8_t
nur ein Typedef für ist unsigned char
, warum also verwenden?
Antworten:
Es dokumentiert Ihre Absicht - Sie speichern kleine Zahlen anstelle eines Zeichens.
Es sieht auch besser aus, wenn Sie andere Typedefs wie uint16_t
oder verwenden int32_t
.
unsigned char
oder signed char
Dokumentation der Absicht, da schmucklos char
zeigt, dass Sie mit Charakteren arbeiten.
unsigned
war unsigned int
per Definition?
char
scheint dies 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 klarstellen, 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.
Um pedantisch zu sein, haben einige Systeme möglicherweise keinen 8-Bit-Typ. Laut Wikipedia :
Eine Implementierung ist erforderlich, um ganzzahlige Typen mit exakter Breite für N = 8, 16, 32 oder 64 genau dann zu definieren, wenn ein Typ vorhanden ist, der die Anforderungen erfüllt. Es ist nicht erforderlich, sie für ein anderes N zu definieren, selbst wenn die entsprechenden Typen unterstützt werden.
Es uint8_t
ist also nicht garantiert, dass es existiert, obwohl dies für alle Plattformen gilt, bei denen 8 Bit = 1 Byte sind. Einige eingebettete Plattformen mögen unterschiedlich sein, aber das wird sehr selten. Einige Systeme definieren char
Typen möglicherweise als 16-Bit. In diesem Fall gibt es wahrscheinlich keinen 8-Bit-Typ.
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.
Ich gehe auch davon aus, dass Sie dies gemeint haben uint8_t
(das Standard-Typedef von C99 im stdint.h
Header) und nicht uint_8
(nicht Teil eines Standards).
uint8_t
(oder dazu tippen) darf . Dies liegt daran, dass der 8-Bit-Typ nicht verwendete Bits in der Speicherdarstellung enthalten würde, die uint8_t
nicht vorhanden sein dürfen.
typedef unsigned integer type uint8_t; // optional
Daher ist im Wesentlichen keine C ++ - Standardkonforme Bibliothek erforderlich, um uint8_t überhaupt zu definieren (siehe Kommentar // optional) )
Der springende Punkt ist, implementierungsunabhängigen Code zu schreiben. unsigned char
Es wird nicht garantiert, dass es sich um einen 8-Bit-Typ handelt. uint8_t
ist (falls verfügbar).
sizeof(unsigned char)
wird 1
für 1 Byte zurückgegeben. aber wenn ein System char und int die gleiche Größe von z. B. 16 Bit haben, sizeof(int)
wird auch zurückgegeben1
Wie Sie sagten, " fast jedes System".
char
ist wahrscheinlich eine der weniger wahrscheinlichen Änderungen, aber sobald Sie anfangen, uint16_t
und Freunde zu verwenden, verwenden Sie uint8_t
Mischungen besser und können sogar Teil eines Codierungsstandards sein.
Nach meiner Erfahrung gibt es zwei Stellen, an denen uint8_t 8 Bit (und uint16_t usw.) bedeuten soll und an denen Felder kleiner als 8 Bit sein können. An beiden Stellen kommt es auf den Speicherplatz an, und beim Debuggen müssen wir uns häufig einen Rohdatenauszug der Daten ansehen und schnell feststellen können, was diese darstellen.
Das erste betrifft HF-Protokolle, insbesondere in Schmalbandsystemen. In dieser Umgebung müssen wir möglicherweise so viele Informationen wie möglich in eine einzelne Nachricht packen. Der zweite ist im Flash-Speicher, wo wir möglicherweise nur sehr begrenzten Speicherplatz haben (z. B. in eingebetteten Systemen). In beiden Fällen können wir eine gepackte Datenstruktur verwenden, in 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 verfügen Sie möglicherweise über ein ARM-Gerät, das mit einem x86-Linux-Server kommuniziert.
Es gibt einige Einschränkungen bei der Verwendung gepackter Strukturen. Das größte Problem ist, dass Sie vermeiden müssen, die Adresse eines Mitglieds zu dereferenzieren. Auf Systemen mit mutibyte-ausgerichteten Wörtern kann dies zu einer falsch ausgerichteten Ausnahme führen - und zu einem Coredump.
Einige Leute werden sich auch Sorgen um die Leistung machen und argumentieren, dass die Verwendung dieser gepackten Strukturen Ihr System verlangsamen wird. Es ist richtig, dass der Compiler hinter den Kulissen Code hinzufügt, um auf die nicht ausgerichteten Datenelemente zuzugreifen. Sie können dies anhand des Assembler-Codes in Ihrer IDE sehen.
Da gepackte Strukturen für die Kommunikation und Datenspeicherung am nützlichsten sind, können die Daten beim Arbeiten damit im Speicher in eine nicht gepackte Darstellung extrahiert werden. Normalerweise müssen wir sowieso nicht mit dem gesamten Datenpaket im Speicher arbeiten.
Hier ist eine relevante Diskussion:
Pragma Pack (1) noch __attribute__ ((ausgerichtet (1))) funktionieren
Ist das __attribute __ ((gepackt)) / #pragma pack von gcc unsicher?
http://solidsmoke.blogspot.ca/2010/07/woes-of-structure-packing-pragma-pack.html
Es gibt wenig. Unter dem Gesichtspunkt 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-Integer-Typ hat, wird dies der Fall sein char
. Alternativ kann es sein, dass es zu diesem Zeitpunkt überhaupt keine gibttypedef
gibt. Zu Tricks umstritten.
Es könnte verwendet werden, um Ihren Code in dem Sinne besser zu dokumentieren, dass klar ist, dass Sie dort 8-Bit-Bytes und sonst nichts benötigen. In der Praxis ist dies jedoch praktisch überall eine vernünftige Erwartung (es gibt DSP-Plattformen, auf denen dies nicht der Fall ist, aber die Wahrscheinlichkeit, dass Ihr Code dort ausgeführt wird, ist gering, und Sie können genauso gut einen Fehler machen, wenn Sie eine statische Zusicherung oben in Ihrem Programm verwenden eine solche Plattform).
unsigned char
in der Lage sein, Werte zwischen 0 und 255 zu halten. Wenn Sie dies in 4 Bits tun können, ist mein Hut vor Ihnen.
uint8_t
zur Implementierung hinzufügen . Ich frage mich, ob Compiler für DSPs mit 16-Bit-Zeichen normalerweise implementiert uint8_t
werden oder nicht.
#include <stdint.h>
und zu verwenden uint8_t
. Wenn die Plattform es hat, wird es Ihnen geben. Wenn die Plattform es nicht hat, wird Ihr Programm nicht kompiliert und der Grund ist klar und unkompliziert.
Das ist zum Beispiel sehr wichtig, wenn Sie einen Netzwerkanalysator schreiben. Paket-Header werden durch die Protokollspezifikation definiert, nicht durch die Funktionsweise des C-Compilers einer bestimmten Plattform.
Auf fast jedem System habe ich uint8_t == unsigned char getroffen, aber dies wird vom C-Standard nicht garantiert. Wenn Sie versuchen, tragbaren Code zu schreiben und es genau darauf ankommt, wie groß der Speicher ist, verwenden Sie uint8_t. Verwenden Sie andernfalls ein Zeichen ohne Vorzeichen.
uint8_t
Entspricht immer dem Bereich und der Größe von unsigned char
und dem Auffüllen (keine), wenn unsigned char
es sich um 8-Bit handelt. Wenn unsigned char
nicht 8-Bit ist, uint8_t
existiert nicht.
unsigned char
es sich um 8-Bit handelt, handelt es sich uint8_t
garantiert um eine typedef
davon und nicht typedef
um eine erweiterte vorzeichenlose Ganzzahl ?
unsigned char/signed char/char
wie der kleinste Typ - nicht kleiner als 8 Bit. unsigned char
hat keine Polsterung. Um uint8_t
zu sein, muss es 8-Bit sein, keine Auffüllung, da aufgrund einer Implementierung ein ganzzahliger Typ bereitgestellt wird: der den Mindestanforderungen von entspricht unsigned char
. "... garantiert ein typedef ..." scheint eine gute Frage zu sein.