Détermination de 32 vs 64 bits en C ++

Je cherche un moyen de déterminer de manière fiable si le code C ++ est compilé en 32 vs 64 bits. Nous avons trouvé ce que nous pensons être une solution raisonnable en utilisant des macros, mais nous étions curieux de savoir si les gens pouvaient penser à des cas où cela pourrait échouer ou s’il existe un meilleur moyen de le faire. Veuillez noter que nous essayons de le faire dans un environnement multi-plateforme, multi-compilateur.

#if ((ULONG_MAX) == (UINT_MAX)) # define IS32BIT #else # define IS64BIT #endif #ifdef IS64BIT DoMy64BitOperation() #else DoMy32BitOperation() #endif 

Merci.

    Malheureusement, il n’y a pas de macro multi-plateforme qui définit 32/64 bits entre les principaux compilateurs. J’ai trouvé le moyen le plus efficace de le faire est la suivante.

    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 si c’est un environnement 64 bits ou non et utilisez-le 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 

    Un autre moyen facile consiste à définir simplement ces variables à partir de la ligne de commande du compilateur.

     template 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(); } int main() { // appropriate function will be selected at comstack time DoMyOperation(); return 0; } 

    Malheureusement, dans un environnement multi-plateformes et à compilateurs croisés, il n’existe pas de méthode unique fiable pour le faire au moment de la compilation.

    • _WIN32 et _WIN64 peuvent parfois être tous deux indéfinis si les parameters du projet sont défectueux ou endommagés (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, parfois, l’intelliSense ne grise pas les parties correctes du code, en fonction du paramètre #define actuel. Cela rend difficile de voir exactement quel #define est utilisé au moment de la compilation.

    Par conséquent, la seule méthode fiable consiste à combiner 3 contrôles simples :

    • 1) Comstackz le réglage du temps et;
    • 2) vérification du temps d’exécution et;
    • 3) Vérification du temps de compilation robuste .

    Vérification simple 1/3: Réglage du temps de compilation

    Choisissez n’importe quelle méthode pour définir la variable #define requirejse. 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 

    Vérification simple 2/3: Vérification de l’exécution

    Dans main (), vérifiez que 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 du temps de compilation robuste

    La règle générale est que “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 (ne sais pas si c’était possible auparavant), vous pouvez convertir la vérification au moment de la compilation en utilisant l’assert statique: 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 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 compter sur la logique (parfois imparfaite) dans 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 fonctionnait parfaitement depuis le premier déploiement en production (il y a 12 mois).

    Vous devriez pouvoir utiliser les macros définies dans stdint.h . En particulier, INTPTR_MAX est exactement la valeur dont vous avez besoin.

     #include  #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 Microsoft ne sont pas stdint.h avec stdint.h . Je ne sais pas pourquoi, puisque 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 commencer. Longs et Ints sont tous les deux 32 bits, que vous compiliez 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 ++ définit uniquement des limites inférieures pour des tailles telles que int, long et void * . Il n’y a aucune garantie que l’int soit 64 bits même lorsqu’il est compilé pour une plate-forme 64 bits. Le modèle permet par exemple 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 plateforme. Votre deuxième meilleure décision portable doit être plus spécifique dans ce qui est 64 bits.

    Les personnes ont déjà suggéré des méthodes qui tenteront de déterminer si le programme est compilé en 32-bit ou en 64-bit .

    Et je veux append que vous pouvez utiliser la fonctionnalité c ++ 11 static_assert pour vous assurer que l’architecture est ce que vous pensez être (“relaxer”).

    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’était pas trop éloignée, mais vous vérifiez seulement si long et int ont 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, et non 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 tout type pour lequel vous avez une macro définie par le système avec la valeur maximale.

    Notez que la norme nécessite de long long pour être 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, la définition d’un symbole 64 et 32 ​​bits sera facile. Vous auriez donc 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 tu ne peux pas faire ça, j’aime l’idée de Jared.

    Je placerais des sources 32 bits et 64 bits dans différents fichiers, puis sélectionnez les fichiers sources appropriés à l’aide du système de génération.