Pregunta

Estoy buscando una manera de determinar con certeza si el código de C ++ está siendo compilado en 32 frente a 64 bits. Hemos llegado al día con lo que creemos que es una solución razonable el uso de macros, pero tenía curiosidad por saber si la gente pudiera pensar en casos en los que esto podría fallar o si hay una mejor manera de hacer esto. Tenga en cuenta que estamos tratando de hacer esto en un multi-plataforma, el medio ambiente compilador múltiple.

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

#ifdef IS64BIT
DoMy64BitOperation()
#else
DoMy32BitOperation()
#endif

Gracias.

¿Fue útil?

Solución

Desafortunadamente, no hay macro multiplataforma que define 32/64 bit a través de las principales compiladores. He encontrado la manera más efectiva de hacerlo es la siguiente.

En primer tomo mi propia representación. Yo prefiero ENVIRONMENT64 / ENVIRONMENT32. Luego me entero de lo que todos los principales compiladores utilizan para determinar si se trata de un entorno de 64 bits o no y el uso que para establecer mi 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

Otra ruta más fácil es establecer simplemente estas variables desde la línea de comandos del compilador.

Otros consejos

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;
}

Por desgracia, en una plataforma cruzada, el medio ambiente compilador cruzado, no existe un método confiable para hacer esto sola puramente en tiempo de compilación.

  • Tanto _WIN32 y _WIN64 veces puede ambos es indefinido, si la configuración del proyecto son defectuosos o dañados (particularmente en Visual Studio 2008 SP1).
  • Un proyecto de la etiqueta "Win32" podría ser ajustado a 64 bits, debido a un error de configuración del proyecto.
  • En Visual Studio 2008 SP1, a veces el IntelliSense no gris a cabo las partes correctas del código, de acuerdo con el # define actual. Esto hace que sea difícil ver exactamente qué #define se utiliza en tiempo de compilación.

Por lo tanto, la método sólo fiable es combinar 3 cheques simples :

  • 1) Compilar tiempo de fraguado y;
  • 2) verificación Runtime y;
  • 3) tiempo de compilación robusto comprobación .

cheque simple 1/3: Compilar el tiempo de fraguado

Elija cualquier método a set # define la variable requerida. Sugiero el método 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

cheque simple 2/3: Tiempo de ejecución de verificación

En main (), doble comprobación para ver si sizeof () tiene sentido:

#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

cheque simple 3/3: controla el tiempo de compilación robusto

La regla general es "cada #define debe terminar en un #else que genera un error".

#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

Actualización 2017-01-17

Comentario de @AI.G:

  

4 años más tarde (no sé si era posible antes) se puede convertir   la comprobación en tiempo de ejecución a tiempo de compilación usando una aserción estática:   static_assert (sizeof (void *) == 4) ;. Ahora todo se hace en tiempo de compilación   :)

Apéndice A

incidentially, las reglas anteriores se pueden adaptar para que todo el código base más fiable:

  • Cada if () sentencia termina en una "cosa" que genera una advertencia o un error.
  • Cada instrucción switch () termina en un "default". Que genera una advertencia o un error

La razón por la que esto funciona bien es que te obliga a pensar en todos los casos por adelantado, y no depender de la lógica (a veces errónea) en la parte "más" para ejecutar el código correcto.

He utilizado esta técnica (entre muchos otros) para escribir un proyecto de 30.000 línea que funcionó a la perfección desde el día en que fue desplegado por primera vez en producción (eso fue hace 12 meses).

Usted debe ser capaz de utilizar las macros definidas en stdint.h . En particular INTPTR_MAX es exactamente el valor que necesita.

#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

Algunos (todos?) Versiones del compilador de Microsoft no vienen con stdint.h. No sé por qué, ya que es un archivo estándar. Aquí hay una versión que puede utilizar: http://msinttypes.googlecode.com/svn/trunk/stdint.h

Eso no funcionará en Windows para un nuevo comienzo. Anhela y son enteros de 32 bits tanto si se está compilando para Windows de 32 bits o 64 bits. Me gustaría pensar comprobar si el tamaño de un puntero es de 8 bytes es probablemente una ruta más fiable.

Usted puede hacer esto:

#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

"Elaborado de 64 bit" no está bien definido en C ++.

C ++ establece únicos límites más bajos para los tamaños tales como int, largo y void *. No hay ninguna garantía de que int es de 64 bits, incluso cuando se compila para una plataforma de 64 bits. El modelo permite por ejemplo 23 ints bits y sizeof(int *) != sizeof(char *)

Hay diferentes para plataformas de 64 bits.

Su mejor apuesta es una prueba específica de la plataforma. Su segundo mejor decisión, portátil debe ser más específico en lo es 64 bits.

Su enfoque no estaba demasiado lejos, pero sólo se están comprobando si long y int son del mismo tamaño. En teoría, ambos podrían ser de 64 bits, en cuyo caso su cheque fallaría, asumiendo tanto a ser de 32 bits. Aquí es un cheque que comprueba efectivamente el tamaño de los mismos tipos, no su tamaño relativo:

#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 principio, puede hacerlo para cualquier tipo para los que tiene una macro definida por el sistema con el valor máximo.

Nota, que la norma requiere long long a ser de al menos 64 bits, incluso en sistemas de 32 bits.

La gente ya se ha sugerido métodos que tratan de determinar si el programa está siendo compilado en 32-bit o 64-bit.

Y quiero añadir que se puede utilizar la c ++ 11 static_assert función para asegurarse de que la arquitectura es lo que creo que es ( "para relajarse").

Así que en el lugar donde se definen las 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

A continuación código funciona bien para la mayoría de los entornos actuales:

  #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 puede utilizar configuraciones de proyectos en todos sus ambientes, que haría que la definición de un símbolo de 64 y 32 bits fácil. Por lo que tendría configuraciones de proyecto como este:

32 bits Depuración
32-bit de lanzamiento
64-bit de depuración
64-bit de lanzamiento

EDIT: Estos son configuraciones genéricas, no targetted configuraciones. Llame a ellos lo que quiera.

Si usted no puede hacer eso, me gusta la idea de Jared.

Me coloco fuentes de 32 bits y de 64 bits en diferentes archivos y luego seleccione los archivos de origen apropiados usando el sistema de construcción.

Estoy añadiendo esta respuesta como un caso de uso y el ejemplo completo para el tiempo de ejecución-prueba prevista en el otra respuesta .

Este es el enfoque que he estado tomando para transportar al usuario final si el programa se compila como de 64 bits o de 32 bits (o de otro, para el caso):

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;
}

Compilar y prueba

g++ -g test.cc
./a.out
My App v0.09 [64-bit]
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top