Der C99-Standard führt die folgenden Datentypen ein. Die Dokumentation zur AVR-Standardbibliothek finden Sie hier .
uint8_t
bedeutet, dass es sich um einen 8-Bit-Typ ohne Vorzeichen handelt.uint_fast8_t
bedeutet, dass es das schnellste int ohne Vorzeichen mit mindestens 8 Bit ist.uint_least8_t
bedeutet, dass es sich um ein Int ohne Vorzeichen mit mindestens 8 Bits handelt.
Ich verstehe uint8_t
und was ist uint_fast8_t
(ich weiß nicht, wie es auf Registerebene implementiert ist).
1.Können Sie erklären, was die Bedeutung von "es ist eine unsigned int
mit mindestens 8 Bits" ist?
2.Wie uint_fast8_t
und uint_least8_t
helfen Sie, die Effizienz / den Code-Speicherplatz im Vergleich zum uint8_t
?
uint8_t
8 Bitsuint_fast8_t
garantiert> = 8 Bits sind, ähnlich wie beiunsigned char
.uint8_t
es auf Systemen ohne nativen 8-Bit-Typ keine gibt. Die anderen beiden werden da sein.Antworten:
uint_least8_t
ist der kleinste Typ mit mindestens 8 Bits.uint_fast8_t
ist der schnellste Typ mit mindestens 8 Bit.Sie können die Unterschiede erkennen, indem Sie sich exotische Architekturen vorstellen. Stellen Sie sich eine 20-Bit-Architektur vor. Es
unsigned int
hat 20 Bits (ein Register) undunsigned char
10 Bits. Diesizeof(int) == 2
Verwendung vonchar
Typen erfordert jedoch zusätzliche Anweisungen, um die Register zu halbieren. Dann:uint8_t
: ist undefiniert (kein 8-Bit-Typ).uint_least8_t
: istunsigned char
der kleinste Typ mit mindestens 8 Bit.uint_fast8_t
: istunsigned int
, weil in meiner imaginären Architektur eine Halbregistervariable langsamer ist als eine Vollregistervariable.quelle
int_fast8_t
eine 32-Bit-Variable haben, müssen Sie vor arithmetrischen Operationen keine Vorzeichenerweiterung durchführen.uintX_fast_t
weniger als 32 Bit zu machen . Sie müssen sich nicht einmal Architekturen vorstellen, umuint8_t
undefiniert zu werden. Nehmen Sie zum Beispiel UNIVAC, das 36-Bit ist. Ich würde annehmen, dass eschar
9-Bit gibt.uint_leastX_t
oderuint_fastX_t
in realen Anwendungen verwendet habe.uintX_t
Ja, sie werden stark genutzt. Es sieht so aus, als wären Menschen nicht sehr interessant für die Portabilität zu exotischen Architekturen. Was erwartet wird, selbst wenn Sie Ihre Nicht-Unterschriften richtig machen, wird Ihr Programm bei tausend verschiedenen Dingen fehlschlagen.uint8_t
bedeutet: gib mir ein vorzeichenloses int von genau 8 bit.uint_least8_t
bedeutet: gib mir den kleinsten Typ von Int ohne Vorzeichen, der mindestens 8 Bits hat. Optimieren Sie für den Speicherverbrauch.uint_fast8_t
bedeutet: gib mir ein vorzeichenloses int von mindestens 8 bit. Wählen Sie einen größeren Typ, wenn mein Programm dadurch aufgrund von Überlegungen zur Ausrichtung schneller wird. Geschwindigkeit optimieren.Im Gegensatz zu den einfachen
int
Typen ist die signierte Version der oben genannten stdint.h-Typen garantiert das Komplement-Format von 2.quelle
stdint.h
garantiert zwei ergänzen. Ich frage mich, wo es beim Schreiben von tragbarem Code helfen wird.stdint.h
sind weniger hilfreich, als man vielleicht möchte, wenn man versucht, tragbaren Code zu schreiben, da sie zwar das Speicherformat mit zwei Komplementen verwenden müssen, dies jedoch nicht bedeutet, dass sie ein Zweierkomplement-Umhüllungsverhalten aufweisen. Beachten Sie auch, dass selbst auf Plattformen mitint
32 Bit das Schreiben eines Werts mit einemint32_t*
und das Lesen mit einemint*
oder umgekehrt nicht garantiert funktioniert.Die Theorie geht ungefähr so:
uint8_t
muss genau 8 Bit betragen, muss aber nicht vorhanden sein. Sie sollten es daher verwenden, wenn Sie sich auf das Modulo-256-Zuweisungsverhalten * einer 8-Bit-Ganzzahl verlassen und wenn Sie einen Kompilierungsfehler bevorzugen, um sich auf obskuren Architekturen schlecht zu verhalten.uint_least8_t
muss der kleinste verfügbare vorzeichenlose Integer-Typ sein, der mindestens 8 Bit speichern kann. Sie würden es verwenden, wenn Sie den Speicherbedarf von Dingen wie großen Arrays minimieren möchten.uint_fast8_t
soll der "schnellste" vorzeichenlose Typ sein, der mindestens 8 Bits speichern kann; Es ist jedoch nicht garantiert, dass es für eine bestimmte Operation auf einem bestimmten Prozessor die schnellste ist. Sie würden es bei der Verarbeitung von Code verwenden, der viele Operationen an dem Wert ausführt.Die Praxis ist, dass die Typen "schnell" und "am wenigsten" nicht viel verwendet werden.
Die "kleinsten" Typen sind nur dann wirklich nützlich, wenn Sie sich für die Portabilität interessieren, um Architekturen mit CHAR_BIT! = 8 zu verschleiern, was die meisten Leute nicht tun.
Das Problem bei den "schnellen" Typen ist, dass "schnellste" schwer zu bestimmen sind. Ein kleinerer Typ kann eine geringere Belastung des Speicher- / Cache-Systems bedeuten, die Verwendung eines Typs, der kleiner als der native ist, erfordert jedoch möglicherweise zusätzliche Anweisungen. Darüber hinaus kann sich das Beste zwischen den Architekturversionen ändern, aber Implementierer möchten in solchen Fällen häufig vermeiden, dass ABI beschädigt wird.
Aus einigen gängigen Implementierungen geht hervor, dass die Definitionen von uint_fastn_t ziemlich willkürlich sind. glibc scheint sie als mindestens die "native Wortgröße" des fraglichen Systems zu definieren, ohne die Tatsache zu berücksichtigen, dass viele moderne Prozessoren (insbesondere 64-Bit-Prozessoren) eine spezifische Unterstützung für schnelle Operationen an Elementen haben, die kleiner als ihr natives Wort sind Größe. IOS definiert sie anscheinend als äquivalent zu den Typen mit fester Größe. Andere Plattformen können variieren.
Alles in allem sollten Sie, wenn die Leistung von straffem Code mit winzigen Ganzzahlen Ihr Ziel ist, Ihren Code auf den Plattformen, die Sie interessieren, mit unterschiedlich großen Typen vergleichen, um herauszufinden, was am besten funktioniert.
* Beachten Sie, dass das Zuweisungsverhalten von Modulo-256 leider nicht immer eine Modulo-256-Arithmetik impliziert, da C eine Fehlfunktion für die Ganzzahl-Promotion aufweist.
quelle
Einige Prozessoren können bei kleineren Datentypen nicht so effizient arbeiten wie bei großen. Zum Beispiel gegeben:
uint32_t foo(uint32_t x, uint8_t y) { x+=y; y+=2; x+=y; y+=4; x+=y; y+=6; x+=y; return x; }
wenn
y
warenuint32_t
ein Compiler für die ARM Cortex-M3 könnte einfach erzeugenadd r0,r0,r1,asl #2 ; x+=(y<<2) add r0,r0,#12 ; x+=12 bx lr ; return x
aber da
y
istuint8_t
der compiler müsste stattdessen generieren:add r0,r0,r1 ; x+=y add r1,r1,#2 ; Compute y+2 and r1,r1,#255 ; y=(y+2) & 255 add r0,r0,r1 ; x+=y add r1,r1,#4 ; Compute y+4 and r1,r1,#255 ; y=(y+4) & 255 add r0,r0,r1 ; x+=y add r1,r1,#6 ; Compute y+6 and r1,r1,#255 ; y=(y+6) & 255 add r0,r0,r1 ; x+=y bx lr ; return x
Der beabsichtigte Zweck der "schnellen" Typen bestand darin, Compilern zu ermöglichen, kleinere Typen, die nicht effizient verarbeitet werden konnten, durch schnellere zu ersetzen. Leider ist die Semantik "schneller" Typen eher schlecht spezifiziert, was wiederum trübe Fragen darüber aufwirft, ob Ausdrücke mit vorzeichenbehafteter oder vorzeichenloser Mathematik bewertet werden.
quelle
Das sollte offensichtlich sein. Dies bedeutet, dass es sich um einen vorzeichenlosen Integer-Typ handelt und dass seine Breite mindestens 8 Bit beträgt. Tatsächlich bedeutet dies, dass es mindestens die Zahlen 0 bis 255 enthalten kann, und es kann definitiv keine negativen Zahlen enthalten, aber es kann möglicherweise Zahlen über 255 enthalten.
Offensichtlich sollten Sie keinen dieser Typen verwenden, wenn Sie eine Zahl außerhalb des Bereichs von 0 bis 255 speichern möchten (und möchten, dass diese tragbar ist).
uint_fast8_t
muss schneller sein, daher sollten Sie dies verwenden, wenn der Code schnell sein soll.uint_least8_t
Auf der anderen Seite ist es erforderlich, dass es keinen Kandidaten mit geringerer Größe gibt. Sie würden dies also verwenden, wenn die Größe das Problem ist.Und natürlich verwenden Sie nur,
uint8_t
wenn Sie unbedingt genau 8 Bit benötigen. Durchuint8_t
die Verwendung wird der Code möglicherweise nicht portierbar, da eruint8_t
nicht vorhanden sein muss (da auf bestimmten Plattformen ein derart kleiner Integer-Typ nicht vorhanden ist).quelle
Die "schnellen" Ganzzahltypen werden als die schnellste verfügbare Ganzzahl mit mindestens der erforderlichen Anzahl von Bits definiert (in Ihrem Fall 8).
Eine Plattform kann festlegen ,
uint_fast8_t
wieuint8_t
dann gibt es absolut keinen Unterschied in der Geschwindigkeit.Der Grund ist, dass es Plattformen gibt, die langsamer sind, wenn sie ihre native Wortlänge nicht verwenden.
quelle