Ich suche nach einer Möglichkeit, zuverlässig festzustellen, ob C ++ - Code in 32 vs 64 Bit kompiliert wird. Wir haben uns eine unserer Meinung nach vernünftige Lösung mit Makros ausgedacht, waren aber neugierig zu wissen, ob die Leute an Fälle denken könnten, in denen dies fehlschlagen könnte, oder ob es einen besseren Weg gibt, dies zu tun. Bitte beachten Sie, dass wir dies in einer plattformübergreifenden Umgebung mit mehreren Compilern versuchen.
#if ((ULONG_MAX) == (UINT_MAX))
# define IS32BIT
#else
# define IS64BIT
#endif
#ifdef IS64BIT
DoMy64BitOperation()
#else
DoMy32BitOperation()
#endif
Vielen Dank.
c++
32bit-64bit
conditional-compilation
Joe Corkery
quelle
quelle
stdint.h
Möglicherweise ist es Ihr Freund, oder Sie müssen möglicherweise eigene geeignete Typedefs entwickeln.Antworten:
Leider gibt es kein plattformübergreifendes Makro, das 32/64 Bit für die wichtigsten Compiler definiert. Ich habe den effektivsten Weg gefunden, dies zu tun, ist der folgende.
Zuerst wähle ich meine eigene Darstellung. Ich bevorzuge ENVIRONMENT64 / ENVIRONMENT32. Dann finde ich heraus, was alle großen Compiler verwenden, um festzustellen, ob es sich um eine 64-Bit-Umgebung handelt oder nicht, und verwende dies, um meine Variablen festzulegen.
Eine andere einfachere Möglichkeit besteht darin, diese Variablen einfach über die Compiler-Befehlszeile festzulegen.
quelle
#if _WIN32 || _WIN64
...#elif __GNUC__
...#else
# error "Missing feature-test macro for 32/64-bit on this compiler."
?quelle
size_t
groß genug ist, um die Größe eines zugewiesenen Objekts im System aufzunehmen. Normalerweise ist es das, was Sie beim bedingten Kompilieren wissen möchten. Wenn es nicht das ist, was Sie wollen, können Sie dieses Snippet mit einem anderen Typ anstelle von verwendensize_t
. Zum Beispiel könnte es seinvoid*
.Leider gibt es in einer plattformübergreifenden, compilerübergreifenden Umgebung keine einzige zuverlässige Methode, um dies nur zur Kompilierungszeit zu tun.
Daher besteht die einzig zuverlässige Methode darin, drei einfache Überprüfungen zu kombinieren :
Einfache Prüfung 1/3: Einstellung der Kompilierungszeit
Wählen Sie eine beliebige Methode, um die erforderliche Variable #define festzulegen. Ich schlage die Methode von @JaredPar vor:
Einfache Prüfung 2/3: Laufzeitprüfung
Überprüfen Sie in main () noch einmal, ob sizeof () sinnvoll ist:
Einfache Prüfung 3/3: Robuste Prüfung der Kompilierungszeit
Die allgemeine Regel lautet: "Jede #define muss mit einer #else enden, die einen Fehler erzeugt."
Update 2017-01-17
Kommentar von
@AI.G
:Anhang A
Im Übrigen können die oben genannten Regeln angepasst werden, um Ihre gesamte Codebasis zuverlässiger zu machen:
Der Grund, warum dies gut funktioniert, besteht darin, dass Sie gezwungen sind, jeden einzelnen Fall im Voraus zu überlegen und sich nicht auf die (manchmal fehlerhafte) Logik im "else" -Teil zu verlassen, um den richtigen Code auszuführen.
Ich habe diese Technik (unter anderem) verwendet, um ein 30.000-Zeilen-Projekt zu schreiben, das vom ersten Tag an (vor 12 Monaten) einwandfrei funktionierte.
quelle
sizeof(void*)
Wird es zur Kompilierungs- oder Laufzeit aufgelöst? Wenn es zur Kompilierungszeit ist, wird zur Laufzeit immer geprüftif(8!=8){...}
.static_assert(sizeof(void*) == 4);
. Jetzt ist alles zur Kompilierungszeit erledigt :)static_assert(sizeof(void*) * CHAR_BIT == 32)
ist ausdrucksvoller und technisch korrekter (obwohl ich keine Architektur kenne, in der Bytes eine andere Anzahl von Bits als 8 haben)Sie sollten in der Lage sein, die in definierten Makros zu verwenden
stdint.h
. InsbesondereINTPTR_MAX
ist genau der Wert, den Sie benötigen.Einige (alle?) Versionen des Microsoft-Compilers werden nicht mitgeliefert
stdint.h
. Ich weiß nicht warum, da es sich um eine Standarddatei handelt. Hier ist eine Version, die Sie verwenden können:http://msinttypes.googlecode.com/svn/trunk/stdint.hquelle
<stdint.h>
und<cstdint>
. Was den gegenwärtigen Stand der Dinge betrifft - die VC ++ - Bibliothek stammt von Dinkumware (tut es immer noch - TR1 wurde ebenfalls von dort übernommen), aber nach dem, was ich in VCBlog gelesen habe, wird es einer ziemlich bedeutenden Umgestaltung unterzogen, um sauber/clr
mit allen MSVC zu kompilieren und zu arbeiten Nicht-Standard-Typen wie__int64
und so weiter - weshalb es nicht so einfach ist, es einfach zu nehmen und in die nächste Compiler-Version zu setzen.Das funktioniert unter Windows zunächst einmal nicht. Longs und Ints sind beide 32-Bit, unabhängig davon, ob Sie für 32-Bit- oder 64-Bit-Fenster kompilieren. Ich würde denken, dass die Überprüfung, ob die Größe eines Zeigers 8 Bytes beträgt, wahrscheinlich eine zuverlässigere Route ist.
quelle
sizeof(void*) == 8 ? Do64Bit() : Do32Bit();
. Das könnte immer noch eine unbenutzte Funktion in der Binärdatei belassen, aber der Ausdruck wird wahrscheinlich nur zu einem Aufruf der "richtigen" Funktion kompiliert.template<int> struct Thing; template<> struct Thing<4> { typedef uint32_t type; }; template<> struct Thing<8> { typedef uint64_t type; }; typedef Thing<sizeof(void*)>::type thingtype;
Sie könnten dies tun:
quelle
quelle
"In 64 Bit kompiliert" ist in C ++ nicht gut definiert.
C ++ legt nur Untergrenzen für Größen wie int, long und fest
void *
. Es gibt keine Garantie dafür, dass int 64-Bit ist, selbst wenn es für eine 64-Bit-Plattform kompiliert wurde. Das Modell erlaubt zB 23 Bitint
s undsizeof(int *) != sizeof(char *)
Es gibt verschiedene Programmiermodelle für 64-Bit-Plattformen.
Ihre beste Wahl ist ein plattformspezifischer Test. Ihre zweitbeste, müssen tragbare Entscheidung spezifischere in sein , was 64 Bit.
quelle
Ihr Ansatz war nicht zu weit entfernt, aber Sie prüfen nur, ob
long
undint
sind Sie gleich groß. Theoretisch könnten beide 64 Bit sein. In diesem Fall würde Ihre Prüfung fehlschlagen, vorausgesetzt, beide sind 32 Bit. Hier ist eine Überprüfung, die tatsächlich die Größe der Typen selbst überprüft, nicht ihre relative Größe:Grundsätzlich können Sie dies für jeden Typ tun, für den Sie ein systemdefiniertes Makro mit dem Maximalwert haben.
Beachten Sie, dass der Standard
long long
auch auf 32-Bit-Systemen mindestens 64 Bit betragen muss.quelle
#include <limits.h>
irgendwo vor Ihren#if
Tests haben.Die Leute haben bereits Methoden vorgeschlagen, die versuchen festzustellen, ob das Programm in
32-bit
oder kompiliert wird64-bit
.Und ich möchte hinzufügen, dass Sie die c ++ 11-Funktion verwenden können
static_assert
, um sicherzustellen, dass die Architektur so ist, wie Sie denken ("zum Entspannen").Also an der Stelle, an der Sie die Makros definieren:
quelle
static_assert(sizeof(void*) * CHAR_BIT == 32)
ist ausdrucksvoller und technisch korrekter (obwohl ich keine Architektur kenne, in der Bytes eine andere Anzahl von Bits als 8 haben)Der folgende Code funktioniert in den meisten aktuellen Umgebungen einwandfrei:
quelle
_WIN64
dass Sie bereits aufgenommen haben<windows.h>
. Mit Visual C ++, dann ist es besser , den eingebauten Compiler definiert zu verwenden:_M_IX86
,_M_X64
,_M_ARM
,_M_ARM64
etc.__ppc64__
,__powerpc64__
und_ARCH_PPC64
. Das fängt auch AIX und andere Plattformen ein.Wenn Sie Projektkonfigurationen in all Ihren Umgebungen verwenden können, würde dies die Definition eines 64- und 32-Bit-Symbols vereinfachen. Sie hätten also folgende Projektkonfigurationen:
32-Bit-Debug
32-Bit-Release
64-Bit-Debug
64-Bit-Release
BEARBEITEN: Dies sind generische Konfigurationen, keine gezielten Konfigurationen. Rufen Sie sie an, wie Sie wollen.
Wenn du das nicht kannst, mag ich Jareds Idee.
quelle
Ich würde 32-Bit- und 64-Bit-Quellen in verschiedenen Dateien platzieren und dann mithilfe des Build-Systems geeignete Quelldateien auswählen.
quelle
-DBUILD_64BIT
. Oft sind bestimmte Dinge sowohl 32- als auch 64-Bit sehr ähnlich, so dass es sehr praktisch sein kann, sie in derselben Datei zu haben.Angelehnt an Contango ‚s ausgezeichnete Antwort oben und es mit‚kombiniert Besseren Makros, Better Flags ‘von Fluent C ++, können Sie tun:
Dann können Sie es wie folgt verwenden:
Oder mit dem zusätzlichen Makro, das ich hinzugefügt habe:
quelle
Ich füge diese Antwort als Anwendungsfall und vollständiges Beispiel für die in einer anderen Antwort beschriebene Laufzeitprüfung hinzu .
Dies ist der Ansatz, den ich gewählt habe, um dem Endbenutzer zu vermitteln, ob das Programm als 64-Bit oder 32-Bit (oder in einem anderen Fall) kompiliert wurde:
version.h
test.cc
Kompilieren und testen
quelle