Leider gibt es in einer plattformübergreifenden, compilerübergreifenden Umgebung keine einzige zuverlässige Methode, um dies nur zur Kompilierungszeit zu tun.
- Sowohl _WIN32 als auch _WIN64 können manchmal beide undefiniert sein, wenn die Projekteinstellungen fehlerhaft oder beschädigt sind (insbesondere in Visual Studio 2008 SP1).
- Ein Projekt mit der Bezeichnung "Win32" kann aufgrund eines Projektkonfigurationsfehlers auf 64-Bit festgelegt werden.
- In Visual Studio 2008 SP1 grauisiert der Intellisense manchmal nicht die richtigen Teile des Codes gemäß der aktuellen #define. Dies macht es schwierig, genau zu erkennen, welche #define zur Kompilierungszeit verwendet wird.
Daher besteht die einzig zuverlässige Methode darin, drei einfache Überprüfungen zu kombinieren :
- 1) Kompilierzeiteinstellung und;
- 2) Laufzeitprüfung und;
- 3) Robuste Überprüfung der Kompilierungszeit .
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:
// Check windows
#if _WIN32 || _WIN64
#if _WIN64
#define ENV64BIT
#else
#define ENV32BIT
#endif
#endif
// Check GCC
#if __GNUC__
#if __x86_64__ || __ppc64__
#define ENV64BIT
#else
#define ENV32BIT
#endif
#endif
Einfache Prüfung 2/3: Laufzeitprüfung
Überprüfen Sie in main () noch einmal, ob sizeof () sinnvoll ist:
#if defined(ENV64BIT)
if (sizeof(void*) != 8)
{
wprintf(L"ENV64BIT: Error: pointer should be 8 bytes. Exiting.");
exit(0);
}
wprintf(L"Diagnostics: we are running in 64-bit mode.\n");
#elif defined (ENV32BIT)
if (sizeof(void*) != 4)
{
wprintf(L"ENV32BIT: Error: pointer should be 4 bytes. Exiting.");
exit(0);
}
wprintf(L"Diagnostics: we are running in 32-bit mode.\n");
#else
#error "Must define either ENV32BIT or ENV64BIT".
#endif
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."
#if defined(ENV64BIT)
// 64-bit code here.
#elif defined (ENV32BIT)
// 32-bit code here.
#else
// INCREASE ROBUSTNESS. ALWAYS THROW AN ERROR ON THE ELSE.
// - What if I made a typo and checked for ENV6BIT instead of ENV64BIT?
// - What if both ENV64BIT and ENV32BIT are not defined?
// - What if project is corrupted, and _WIN64 and _WIN32 are not defined?
// - What if I didn't include the required header file?
// - What if I checked for _WIN32 first instead of second?
// (in Windows, both are defined in 64-bit, so this will break codebase)
// - What if the code has just been ported to a different OS?
// - What if there is an unknown unknown, not mentioned in this list so far?
// I'm only human, and the mistakes above would break the *entire* codebase.
#error "Must define either ENV32BIT or ENV64BIT"
#endif
Update 2017-01-17
Kommentar von @AI.G
:
4 Jahre später (ich weiß nicht, ob es vorher möglich war) können Sie die Laufzeitprüfung mit static assert: static_assert (sizeof (void *) == 4); in die Kompilierungszeit konvertieren. Jetzt ist alles zur Kompilierungszeit erledigt :)
Anhang A
Im Übrigen können die oben genannten Regeln angepasst werden, um Ihre gesamte Codebasis zuverlässiger zu machen:
- Jede if () - Anweisung endet mit einem "else", das eine Warnung oder einen Fehler generiert.
- Jede switch () - Anweisung endet mit einem "default:", der eine Warnung oder einen Fehler generiert.
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.