Je cherche un moyen de déterminer de manière fiable si le code C++ est compilé en version 32 vs 64 bits. Nous avons proposé ce que nous pensons être une solution raisonnable en utilisant des macros, mais nous étions curieux de savoir si les gens pouvaient penser aux cas où cela pourrait échouer ou s'il existe une meilleure façon de le faire. Veuillez noter que nous essayons de le faire dans un environnement de compilateur multiplate-forme et multiplate-forme.
#if ((ULONG_MAX) == (UINT_MAX))
# define IS32BIT
#else
# define IS64BIT
#endif
#ifdef IS64BIT
DoMy64BitOperation()
#else
DoMy32BitOperation()
#endif
Merci.
Malheureusement, il n’existe pas de macro multiplate-forme définissant 32/64 bits entre les principaux compilateurs. J'ai trouvé le moyen le plus efficace de procéder est le suivant.
Je choisis d'abord ma propre représentation. Je préfère ENVIRONMENT64/ENVIRONMENT32. Ensuite, je découvre ce que tous les principaux compilateurs utilisent pour déterminer s’il s’agit ou non d’un environnement 64 bits et l’utilise pour définir mes variables.
// Check windows
#if _WIN32 || _WIN64
#if _WIN64
#define ENVIRONMENT64
#else
#define ENVIRONMENT32
#endif
#endif
// Check GCC
#if __GNUC__
#if __x86_64__ || __ppc64__
#define ENVIRONMENT64
#else
#define ENVIRONMENT32
#endif
#endif
Une autre solution plus simple consiste à définir simplement ces variables à partir de la ligne de commande du compilateur.
template<int> void DoMyOperationHelper();
template<> void DoMyOperationHelper<4>()
{
// do 32-bits operations
}
template<> void DoMyOperationHelper<8>()
{
// do 64-bits operations
}
// helper function just to hide clumsy syntax
inline void DoMyOperation() { DoMyOperationHelper<sizeof(size_t)>(); }
int main()
{
// appropriate function will be selected at compile time
DoMyOperation();
return 0;
}
Malheureusement, dans un environnement multi-plateformes et multi-compilateur, il n’existe pas de méthode fiable permettant de le faire uniquement au moment de la compilation.
Par conséquent, la méthode only fiable consiste à combiner 3 contrôles simples:
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
Dans main (), vérifiez si sizeof () est logique:
#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
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
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 lors de la compilation en utilisant l'assert statique: static_assert (sizeof (void *) == 4) ;. Maintenant tout est fait au moment de la compilation :)
Incidemment, les règles ci-dessus peuvent être adaptées pour rendre votre base de code plus fiable:
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 "sinon" 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 fonctionné sans faille depuis le jour où il a été déployé pour la première fois en production (c'était il y a 12 mois).
Vous devriez pouvoir utiliser les macros définies dans stdint.h
. INTPTR_MAX
est en particulier exactement la valeur dont vous avez besoin.
#include <cstdint>
#if INTPTR_MAX == INT32_MAX
#define THIS_IS_32_BIT_ENVIRONMENT
#Elif INTPTR_MAX == INT64_MAX
#define THIS_IS_64_BIT_ENVIRONMENT
#else
#error "Environment not 32 or 64-bit."
#endif
Certaines versions (toutes?) Du compilateur de Microsoft ne viennent pas avec stdint.h
. Vous ne savez pas pourquoi, car c'est un fichier standard. Voici une version que vous pouvez utiliser: http://msinttypes.googlecode.com/svn/trunk/stdint.h
Cela ne fonctionnera pas sous Windows pour un début. Les longueurs et les bits sont en 32 bits, que vous compiliez pour des fenêtres 32 bits ou 64 bits. Je pense que vérifier si la taille d'un pointeur est de 8 octets est probablement un itinéraire plus fiable.
Vous pourriez faire ceci:
#if __WORDSIZE == 64
char *size = "64bits";
#else
char *size = "32bits";
#endif
Try this:
#ifdef _WIN64
// 64 bit code
#Elif _WIN32
// 32 bit code
#else
if(sizeof(void*)==4)
// 32 bit code
else
// 64 bit code
#endif
"Compilé en 64 bits" n'est pas bien défini en C++.
C++ ne définit que des limites inférieures pour les tailles telles que int, long et void *
. Il n'y a aucune garantie que int soit en 64 bits même lorsqu'il est compilé pour une plateforme 64 bits. Le modèle permet par exemple de 23 bits int
s et sizeof(int *) != sizeof(char *)
Il existe différents modèles de programmation pour les plates-formes 64 bits.
Votre meilleur pari est un test spécifique à la plate-forme. Votre deuxième choix, la décision portable doit être plus spécifique en quoi est de 64 bits.
Des personnes ont déjà suggéré des méthodes pour tenter de déterminer si le programme est en cours de compilation en 32-bit
ou 64-bit
.
Et je tiens à ajouter que vous pouvez utiliser la fonctionnalité c ++ 11 static_assert
pour vous assurer que l’architecture correspond à ce que vous pensez ("se détendre").
Donc, à l'endroit où vous définissez les macros:
#if ...
# define IS32BIT
static_assert(sizeof(void *) == 4, "Error: The Arch is not what I think it is")
#Elif ...
# define IS64BIT
static_assert(sizeof(void *) == 8, "Error: The Arch is not what I think it is")
#else
# error "Cannot determine the Arch"
#endif
Votre approche n’est pas très éloignée, mais vous ne faites que vérifier si long
et int
sont de la même taille. Théoriquement, ils pourraient tous deux être de 64 bits, auquel cas votre vérification échouerait, en supposant que les deux soient de 32 bits. Voici une vérification qui vérifie réellement la taille des types eux-mêmes, pas leur taille relative:
#if ((UINT_MAX) == 0xffffffffu)
#define INT_IS32BIT
#else
#define INT_IS64BIT
#endif
#if ((ULONG_MAX) == 0xfffffffful)
#define LONG_IS32BIT
#else
#define LONG_IS64BIT
#endif
En principe, vous pouvez le faire pour tous les types pour lesquels vous avez une macro définie par le système avec la valeur maximale.
Notez que la norme exige que long long
soit au moins 64 bits, même sur les systèmes 32 bits.
Le code ci-dessous fonctionne bien pour la plupart des environnements actuels:
#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)
#define IS64BIT 1
#else
#define IS32BIT 1
#endif
Si vous pouvez utiliser des configurations de projet dans tous vos environnements, cela facilitera la définition d'un symbole 64 et 32 bits. Donc, vous auriez des configurations de projet comme ceci:
Débogage 32 bits
Version 32 bits
Débogage 64 bits
Version 64 bits
EDIT: Ce sont des configurations génériques, pas des configurations ciblées. Appelez-les comme vous voulez.
Si vous ne pouvez pas faire ça, j'aime bien l'idée de Jared.
Je placerais les sources 32 bits et 64 bits dans des fichiers différents, puis sélectionnerais les fichiers source appropriés à l'aide du système de construction.
J'ajoute cette réponse en tant que cas d'utilisation et complète l'exemple de la vérification d'exécution décrite dans une autre réponse .
C’est l’approche que j’ai choisie pour indiquer à l’utilisateur final si le programme a été compilé au format 64 bits ou 32 bits (ou autre, d’ailleurs):
version.h
#ifndef MY_VERSION
#define MY_VERSION
#include <string>
const std::string version = "0.09";
const std::string Arch = (std::to_string(sizeof(void*) * 8) + "-bit");
#endif
test.cc
#include <iostream>
#include "version.h"
int main()
{
std::cerr << "My App v" << version << " [" << Arch << "]" << std::endl;
}
Compiler et tester
g++ -g test.cc
./a.out
My App v0.09 [64-bit]