Nach meinem Verständnis sollte int
es sich ursprünglich um einen "nativen" Integer-Typ mit zusätzlicher Garantie handeln, dass er mindestens 16 Bit groß sein sollte - etwas, das damals als "vernünftige" Größe galt.
Als 32-Bit-Plattformen häufiger wurden, können wir sagen, dass sich die "angemessene" Größe auf 32 Bit geändert hat:
- Modernes Windows verwendet 32-Bit
int
auf allen Plattformen.
- POSIX garantiert
int
mindestens 32 Bit.
- C #, Java hat einen Typ,
int
der garantiert genau 32 Bit beträgt.
Aber als die 64-Bit-Plattform zur Norm wurde, wurde niemand int
zu einer 64-Bit-Ganzzahl erweitert, weil:
- Portabilität: Viel Code hängt von
int
der Größe von 32 Bit ab.
- Speicherverbrauch: Eine Verdoppelung der Speichernutzung ist
int
in den meisten Fällen möglicherweise nicht zumutbar, da in den meisten Fällen die verwendeten Zahlen viel kleiner als 2 Milliarden sind.
Nun, warum wollen Sie uint32_t
zu uint_fast32_t
? Aus dem gleichen Grund verwenden Sprachen, C # und Java immer Ganzzahlen mit fester Größe: Der Programmierer schreibt keinen Code und denkt über mögliche Größen unterschiedlicher Typen nach. Er schreibt für eine Plattform und testet Code auf dieser Plattform. Der größte Teil des Codes hängt implizit von bestimmten Größen der Datentypen ab. Und deshalb uint32_t
ist es in den meisten Fällen eine bessere Wahl - es lässt keine Unklarheiten hinsichtlich seines Verhaltens zu.
Ist es uint_fast32_t
wirklich der schnellste Typ auf einer Plattform mit einer Größe von 32 Bit oder mehr? Nicht wirklich. Betrachten Sie diesen Code-Compiler von GCC für x86_64 unter Windows:
extern uint64_t get(void);
uint64_t sum(uint64_t value)
{
return value + get();
}
Die generierte Baugruppe sieht folgendermaßen aus:
push
sub $0x20,
mov
callq d <sum+0xd>
add
add $0x20,
pop
retq
Wenn Sie nun get()
den Rückgabewert auf uint_fast32_t
(unter Windows x86_64 4 Byte) ändern , erhalten Sie Folgendes:
push %rbx
sub $0x20,%rsp
mov %rcx,%rbx
callq d <sum+0xd>
mov %eax,%eax ; <-- additional instruction
add %rbx,%rax
add $0x20,%rsp
pop %rbx
retq
Beachten Sie, dass der generierte Code fast identisch ist, mit Ausnahme zusätzlicher mov %eax,%eax
Anweisungen nach dem Funktionsaufruf, mit denen der 32-Bit-Wert in einen 64-Bit-Wert erweitert werden soll.
Es gibt kein solches Problem, wenn Sie nur 32-Bit-Werte verwenden, aber Sie werden wahrscheinlich solche mit size_t
Variablen verwenden (Array-Größen wahrscheinlich?) Und diese sind 64-Bit auf x86_64. Unter Linux sind uint_fast32_t
es 8 Bytes, daher ist die Situation anders.
Viele Programmierer verwenden, int
wenn sie einen kleinen Wert zurückgeben müssen (sagen wir im Bereich [-32,32]). Dies würde perfekt funktionieren, wenn int
es sich um eine native Ganzzahlgröße für Plattformen handelt. Da es sich jedoch nicht um eine 64-Bit-Plattform handelt, ist ein anderer Typ, der dem nativen Plattformtyp entspricht, die bessere Wahl (es sei denn, er wird häufig mit anderen Ganzzahlen kleinerer Größe verwendet).
Grundsätzlich ist, unabhängig davon, was der Standard sagt, uint_fast32_t
bei einigen Implementierungen ohnehin ein Fehler aufgetreten. Wenn Sie sich für zusätzliche Anweisungen interessieren, die an einigen Stellen generiert werden, sollten Sie Ihren eigenen "nativen" Ganzzahltyp definieren. Oder Sie können es size_t
für diesen Zweck verwenden, da es normalerweise der native
Größe entspricht (ich schließe keine alten und undurchsichtigen Plattformen wie 8086 ein, sondern nur Plattformen, auf denen Windows, Linux usw. ausgeführt werden können).
Ein weiteres Zeichen, das anzeigt, dass int
es sich um einen nativen Ganzzahltyp handeln sollte, ist die "Ganzzahl-Heraufstufungsregel". Die meisten CPUs können nur Operationen auf nativen Systemen ausführen, sodass 32-Bit-CPUs normalerweise nur 32-Bit-Additionen, Subtraktionen usw. ausführen können (Intel-CPUs sind hier eine Ausnahme). Ganzzahlige Typen anderer Größen werden nur durch Lade- und Speicheranweisungen unterstützt. Beispielsweise sollte der 8-Bit-Wert mit der entsprechenden Anweisung "8-Bit-Vorzeichen laden" oder "8-Bit-Vorzeichen laden" geladen werden und wird nach dem Laden auf 32 Bit erweitert. Ohne die Ganzzahl-Heraufstufungsregel müssten C-Compiler etwas mehr Code für Ausdrücke hinzufügen, die Typen verwenden, die kleiner als der native Typ sind. Leider gilt dies bei 64-Bit-Architekturen nicht mehr, da Compiler in einigen Fällen zusätzliche Anweisungen ausgeben müssen (wie oben gezeigt).