Malheureusement, dans un environnement multiplateforme et compilateur croisé, il n'existe pas de méthode fiable unique pour le faire uniquement au moment de la compilation.
- _WIN32 et _WIN64 peuvent parfois être tous deux indéfinis, si les paramètres du projet sont défectueux ou corrompus (en particulier sur Visual Studio 2008 SP1).
- Un projet intitulé "Win32" peut être défini sur 64 bits, en raison d'une erreur de configuration du projet.
- Sur Visual Studio 2008 SP1, l'intellisense ne grise parfois pas les parties correctes du code, selon la #define actuelle. Cela rend difficile de voir exactement quelle #define est utilisée au moment de la compilation.
Par conséquent, la seule méthode fiable consiste à combiner 3 vérifications simples :
- 1) réglage de l'heure de compilation , et;
- 2) contrôle d'exécution , et;
- 3) Vérification robuste du temps de compilation .
Contrôle simple 1/3: réglage de l'heure de compilation
Choisissez n'importe quelle méthode pour définir la variable #define requise. Je suggère la méthode de @JaredPar:
// 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
Contrôle simple 2/3: contrôle d'exécution
Dans main (), revérifiez pour voir si sizeof () a du sens:
#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
Vérification simple 3/3: Vérification robuste du temps de compilation
La règle générale est "chaque #define doit se terminer par un #else qui génère une erreur".
#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
Mise à jour 2017-01-17
Commentaire de @AI.G
:
4 ans plus tard (je ne sais pas si c'était possible auparavant), vous pouvez convertir la vérification à l'exécution en une vérification à la compilation en utilisant static assert: static_assert (sizeof (void *) == 4) ;. Maintenant, tout est fait au moment de la compilation :)
Annexe A
Incidemment, les règles ci-dessus peuvent être adaptées pour rendre l'ensemble de votre base de code plus fiable:
- Chaque instruction if () se termine par un "else" qui génère un avertissement ou une erreur.
- Chaque instruction switch () se termine par un "default:" qui génère un avertissement ou une erreur.
La raison pour laquelle cela fonctionne bien est que cela vous oblige à penser à chaque cas à l'avance, et à ne pas vous fier à la logique (parfois imparfaite) de la partie «else» pour exécuter le code correct.
J'ai utilisé cette technique (parmi beaucoup d'autres) pour écrire un projet de 30 000 lignes qui a parfaitement fonctionné depuis le jour où il a été déployé pour la première fois en production (il y a 12 mois).