2016-03-22 7 views
12

In C++ 11 stehen uns Integer-Typen mit fester Breite zur Verfügung, z. B. std::int32_t und std::int64_t, die optional sind und daher nicht optimal zum Schreiben von plattformübergreifendem Code geeignet sind. Wir haben jedoch auch nicht optionale Varianten für die Typen: z.B. die "schnellen" Varianten, z.B. std::int_fast32_t und std::int_fast64_t, sowie die "kleinsten" Varianten, z.B. std::int_least32_t, die beide mindestens die angegebene Anzahl von Bits in der Größe sind.Gibt es einen Grund, C++ 11 std :: int_fast32_t oder std :: int_fast16_t über int in plattformübergreifendem Code zu verwenden?

Der Code, an dem ich arbeite, ist Teil einer C++ 11-basierten plattformübergreifenden Bibliothek, die die Kompilierung für die gängigsten Unix/Windows/Mac-Compiler unterstützt. Eine Frage, die jetzt auftaucht, ist, ob es einen Vorteil beim Ersetzen der vorhandenen Integer-Typen im Code durch die C++ 11-Integer-Typen mit fester Breite gibt.

Ein Nachteil von Variablen wie std::int16_t und std::int32_t ist die fehlende Garantie verwendet, dass sie verfügbar sind, da sie nur dann, wenn die Umsetzung unmittelbar den Typ (gemäß http://en.cppreference.com/w/cpp/types/integer) unterstützt vorgesehen sind.

Jedoch, seit int ist mindestens 16 Bits und 16-Bit sind groß genug für die Ganzzahlen im Code verwendet, was ist mit der Verwendung von std::int_fast16_t über int? Bietet es einen Vorteil, alle int Typen durch std::int_fast16_t und alle unsigned int durch std::uint_fast16_t auf diese Weise zu ersetzen oder ist das unnötig?

Anologously, wenn zu wissen, dass alle unterstützten Plattformen und Compiler verfügen über eine int von mindestens 32 Bit Größe, ist es sinnvoll, sie zu ersetzen durch std::int_fast32_t und std::uint_fast32_t jeweils?

+4

Ihr "Nachteil" scheint auf einer Annahme zu beruhen. Wer sagt, dass 'std :: int16_t' und' std :: int32_t' verschwinden könnten? Schließlich werden sie vom * Standard * benötigt. –

+3

Wenn Sie sicher sein wollen, dass Ihr Int mindestens 32 Bit breit ist, tun Sie es. Normal 'int' gibt keine solche Garantie. –

+3

@GregHewgill sie sind optional. Ich meine, dass sie in zukünftigen Versionen eines OS & Compilers möglicherweise nicht unterstützt werden, wenn sie dort zuvor unterstützt wurden. Mir ist kein OS & Compiler bekannt, der nicht std :: int16_t und std :: int32_t liefert, aber da sie nur optional sind, wenn eine ganze Zahl dieser Größe bereits nativ existiert, kann ihre Existenz nicht garantiert werden. Siehe auch: http: // stackoverflow.com/questions/32155759/state-of-support-für-die-optional-fixed-width-integer-types-eingeführt-in-c11, wo Sie antworten können, wenn Sie mehr wissen :) – Ident

Antwort

20

int kann 16, 32 oder sogar 64 Bit auf aktuellen Computern und Compilern sein. In Zukunft könnte es größer sein (zB 128 Bit).

Wenn Ihr Code in Ordnung ist, gehen Sie mit ihm.

Wenn Ihr Code nur mit 32-Bit-Ints getestet und verwendet wird, sollten Sie die Verwendung von int32_t in Erwägung ziehen. Dann wird der Code zur Kompilierungszeit statt zur Laufzeit fehlschlagen, wenn er auf einem System ausgeführt wird, das keine 32-Bit-Ints hat (was heutzutage extrem selten ist).

int_fast32_t ist, wenn Sie mindestens 32 Bits benötigen, aber Sie interessieren sich sehr für die Leistung. Auf Hardware, bei der eine 32-Bit-Ganzzahl als eine 64-Bit-Ganzzahl geladen wird, dann in einem beschwerlichen Prozess auf eine 32-Bit-Ganzzahl zurückgeschoben wird, kann die int_fast_32_t eine 64-Bit-Ganzzahl sein. Die Kosten dafür sind, dass sich der Code auf obskuren Plattformen sehr unterschiedlich verhält.

Wenn Sie nicht auf solchen Plattformen testen, würde ich davon abraten.

Es ist in der Regel besser, Dinge zum Zeitpunkt der Erstellung zu unterbrechen, als wenn sie zur Laufzeit unterbrochen werden. Wenn und wenn Ihr Code tatsächlich auf einem obskuren Prozessor ausgeführt wird, der diese Funktionen benötigt, beheben Sie ihn mit . Es gilt die Regel "Sie werden es wahrscheinlich nicht brauchen".

Seien Sie vorsichtig, generieren Sie frühe Fehler auf der Hardware, auf der Sie nicht getestet werden, und wenn Sie diese Hardware portieren müssen, sind die erforderlichen Arbeiten und Tests erforderlich.

Kurz:

Verwenden int_fast##_t, wenn und nur wenn Sie getestet Code (und wird auch weiterhin testen) auf Plattformen, auf denen die int Größe variiert, und Sie haben gezeigt, dass die Leistungsverbesserung wert ist diese zukünftige Wartung.

Die Verwendung von int##_t mit gemeinsamen ## Größen bedeutet, dass Ihr Code nicht auf Plattformen kompiliert werden kann, auf denen Sie ihn nicht getestet haben. Das ist gut; Ungeprüfter Code ist nicht zuverlässig und unzuverlässiger Code ist normalerweise schlechter als nutzlos.

Ohne int32_t und unter Verwendung int, Ihr Code wird manchmal int s, die 32 sind und manchmal Ints, der 64 (und in der Theorie mehr) sind, und manchmal int s, die 16 sind, wenn Sie bereit sind, zu testen und Unterstützen Sie jeden solchen Fall in jedem solchen int, gehen Sie dafür.

Beachten Sie, dass Arrays von int_fast##_t Cache-Probleme haben können: Sie könnten unverhältnismäßig groß sein. Als ein Beispiel könnte int_fast16_t 64 Bits sein. Ein Array von ein paar tausend oder Millionen von ihnen könnte individuell schnell arbeiten, aber die Cache-Misses, verursacht durch ihre Masse, könnten sie insgesamt langsamer machen; und das Risiko, dass Dinge auf langsameren Speicher ausgelagert werden, wächst.

int_least##_t kann in diesen Fällen schneller sein.

Dasselbe gilt doppelt für netzwerkübertragene und Datei-gespeicherte Daten, zusätzlich zu dem offensichtlichen Problem, dass Netzwerk-/Dateidaten normalerweise Formaten folgen müssen, die stabil gegenüber Compiler/Hardware-Änderungen sind. Dies ist jedoch eine andere Frage.

Bei der Verwendung von Integer-Typen mit fester Breite muss jedoch besonders darauf geachtet werden, dass int, long usw. immer noch dieselbe Breite wie zuvor haben. Integer-Heraufstufung erfolgt immer noch basierend auf der Größe von int, die von dem verwendeten Compiler abhängt. Eine Ganzzahl in Ihrem Code hat den Typ int und die zugehörige Breite. Dies kann zu unerwünschtem Verhalten führen, wenn Sie Ihren Code mit einem anderen Compiler kompilieren. Für ausführlichere Informationen: https://stackoverflow.com/a/13424208/3144964

+0

Zuerst, danke für die schnelle und hilfreiche Antwort! Leider hast du diese Antwort so schnell geschrieben, dass ich immer noch einen Fehler behebe, den ich in meiner Frage gemacht habe (vergessen habe, die Annahme zu erwähnen, dass die Ints in den unterstützten Systemen mindestens 32 Bit sind) und nun wird die Frage ein wenig erweitert. Das tut mir leid. – Ident

+0

@ident Ich habe einen oder zwei Absätze hinzugefügt. – Yakk

+1

Sie sollten die Anwendungsfälle für 'int_leastxx *' und 'int_fast' hervorheben. Am schnellsten ist vielleicht nicht das Beste, wenn Sie solche Ganzzahlen speichern müssen, nichts hindert sizeof (int_fast32_t) daran, unangemessen groß zu sein, was es aufgrund des Caches möglicherweise langsamer als "int_least32_t" gemacht hat. – sbabbi

1

Ich habe gerade festgestellt, dass das OP nur über int_fast##_t nicht int##_t fragt, da das spätere optional ist. Allerdings werde ich die Antwort behalten, es kann jemandem helfen.


Ich würde etwas hinzufügen. Ganzzahlige Ganzzahlen mit fester Größe sind so wichtig (oder sogar ein Muss), um APIs für andere Sprachen zu erstellen. Ein Beispiel ist, wenn Sie möchten pInvoke Funktionen und übergeben Sie Daten an sie in einer nativen C++ DLL von einem .NET verwalteten Code zum Beispiel. In .NET, int ist garantiert eine feste Größe (ich denke, es ist 32bit). Wenn Sie int in C++ verwendet haben und es als 64-Bit und nicht als 32-Bit angesehen wurde, kann dies zu Problemen führen und die Reihenfolge der Wrapped-Strukturen reduzieren.

Verwandte Themen