Es ist normalerweise besser, CPU-Register mit ihrer vollen Kapazität zu nutzen. Für ein portables Stück Code bedeutet dies die Verwendung von 64-Bit-Arithmetik und -Speicherung auf einer 64-Bit-CPU und nur 32-Bit auf einer 32-Bit-CPU (andernfalls werden 64-Bit-Anweisungen im 32-Bit-Modus emuliert, was zu verheerende Leistungen).
Das bedeutet, dass es notwendig ist, die Größe der CPU-Register zu erkennen, typischerweise zur Kompilierzeit (da Laufzeittests teuer sind).
Seit Jahren verwende ich die einfache Heuristik sizeof(nativeRegisters) == sizeof(size_t)
.
Es hat für viele Plattformen gut funktioniert, aber es scheint eine falsche Heuristik für Linux zu sein x32 : in diesem Fall, size_t
ist nur 32 Bit, während Register immer noch 64 Bit verarbeiten könnten. Dies führt zu einer verlorenen Leistungsmöglichkeit (wichtig für meinen Anwendungsfall).
Ich möchte die nutzbare Größe von CPU-Registern auch in einer solchen Situation korrekt erkennen.
Ich vermute, ich könnte versuchen, ein Compiler-spezifisches Makro für Sonderfälle zu finden x32 Modus. Aber ich habe mich gefragt, ob es etwas Allgemeineres geben würde, um mehr Situationen abzudecken. Ein anderes Ziel wäre zum Beispiel OpenVMS 64-Bit: Dort beträgt die native Registergröße 64-Bit, aber size_t
ist nur 32 Bit.
Es gibt keinen zuverlässigen und tragbaren Weg, um die Registergröße von C zu bestimmen. C hat nicht einmal ein Konzept von “Registern” (die Beschreibung der register
Schlüsselwort erwähnt keine CPU-Register).
Aber es definiert eine Reihe von Integer-Typen, die die sind am schnellsten Art von mindestens einer bestimmten Größe. <stdint.h>
definiert uint_fastN_t
zum N = 8, 16, 32, 64.
Wenn Sie davon ausgehen, dass Register mindestens 32 Bit haben, dann uint_fast32_t
hat wahrscheinlich die gleiche Größe wie ein Register, entweder 32 oder 64 Bit. Dies ist nicht garantiert. Hier ist, was die Norm sagt:
Jeder der folgenden Typen bezeichnet einen ganzzahligen Typ, mit dem normalerweise am schnellsten gearbeitet werden kann, unter allen ganzzahligen Typen, die mindestens die angegebene Breite haben.
mit Fußnote:
Es ist nicht garantiert, dass der angegebene Typ für alle Zwecke am schnellsten ist; Wenn die Implementierung keinen klaren Grund hat, einen Typ einem anderen vorzuziehen, wählt sie einfach einen ganzzahligen Typ aus, der die Vorzeichen- und Breitenanforderungen erfüllt.
In der Tat schlage ich vor, dass Sie die verwenden [u]int_fastN_t
types drückt Ihre Absicht deutlicher aus als der Versuch, die CPU-Registergröße anzupassen.
Wenn das für ein bestimmtes Ziel nicht funktioniert, müssen Sie einen Sonderfall hinzufügen
#if
oder #ifdef
Anweisungen zur Auswahl eines geeigneten Typs. Aber uint_fast32_t
(oder uint_fast16_t
wenn Sie 16-Bit-Systeme unterstützen möchten) ist wahrscheinlich ein besserer Ausgangspunkt als size_t
oder int
.
Ein schnelles Experiment zeigt das, wenn ich mit kompiliere gcc -mx32
beide uint_fast16_t
und uint_fast32_t
sind 32 Bit. Sie sind beide 64 Bit, wenn sie ohne kompiliert werden -mx32
(auf meinem x86_64-System). Was bedeutet, dass zumindest für gcc die uint_fastN_t
Typen nicht Tun Sie, was Sie wollen. Sie benötigen einen Sonderfallcode für x32. (Wahrscheinlich gcc sollte Verwenden Sie 64-Bit-Typen für uint_fastN_t
im x32-Modus. Ich habe gerade diese Frage gepostet und danach gefragt.)
Diese Frage fragt, wie eine x32-Umgebung im Präprozessor erkannt werden kann. gcc bietet keine direkte Möglichkeit, dies festzustellen, aber ich habe gerade eine Antwort gepostet, die die Verwendung von vorschlägt __x86_64__
und SIZE_MAX
Makros.
Unser Interesse, wie können Sie “die Antwort” in C – Assembly verwenden, die ich bekomme, aber C?
– John3136
30. April 2016 um 8:12 Uhr
Es liegt am Algorithmus. Verwenden Sie eine genauere 64-Bit-Arithmetik anstelle einer billigeren 32-Bit-Heuristik. Verwenden Sie Register als “schnellen lokalen Speicher” für längere Zeit, wenn 64-Bit im Vergleich zu 32-Bit verwendet werden. Die Auswahl erfolgt zur Kompilierzeit mit test of
sizeof(size_t)
(bis jetzt).– Cyan
30. April 2016 um 8:14 Uhr
Ein weiterer beliebter ist
sizeof(void*)
.– Sergej Kalinitschenko
30. April 2016 um 8:22 Uhr
Es gibt keine zuverlässige Möglichkeit, die Registergröße von der einfachen C-Ebene aus zu ermitteln. Aber von den Definitionen der Sprache sollte die nächste Vermutung sein sizeof(int) wie int soll der natürliche Typ für die Umwelt sein. (Andere Typen sind bereits an einen anderen Zweck gebunden.) Auch dann werden Ihnen einige Compiler-Einstellungen folgen.
– rpi
30. April 2016 um 8:44 Uhr
@rpy: In Linux, Windows und MacOS X für 64-Bit-Ziele sizeof(int)==4 wie in ihren ABIs definiert. Also nein, int ist kein guter Indikator. Dann unter Windows sizeof(long)==4 und unter Linux sizeof(long)==8.
– Datenwolf
30. April 2016 um 10:55 Uhr