Estoy buscando una manera de determinar de manera confiable si el código C ++ se está compilando en 32 contra 64 bits. Se nos ocurrió lo que creemos que es una solución razonable utilizando macros, pero tenía curiosidad por saber si la gente podría pensar en casos en los que esto podría fallar o si hay una mejor manera de hacerlo. Tenga en cuenta que estamos tratando de hacer esto en un entorno multiplataforma y compilador múltiple.
#if ((ULONG_MAX) == (UINT_MAX))
# define IS32BIT
#else
# define IS64BIT
#endif
#ifdef IS64BIT
DoMy64BitOperation()
#else
DoMy32BitOperation()
#endif
Gracias.
c++
32bit-64bit
conditional-compilation
Joe Corkery
fuente
fuente
stdint.h
puede ser tu amigo, o puede que necesites desarrollar algunos tipos de letra apropiados.Respuestas:
Desafortunadamente, no existe una macro multiplataforma que defina 32/64 bits en los principales compiladores. He encontrado que la forma más efectiva de hacer esto es la siguiente.
Primero elijo mi propia representación. Prefiero ENVIRONMENT64 / ENVIRONMENT32. Luego descubro lo que utilizan todos los compiladores principales para determinar si es un entorno de 64 bits o no y lo uso para establecer mis variables.
Otra ruta más fácil es simplemente establecer estas variables desde la línea de comandos del compilador.
fuente
#if _WIN32 || _WIN64
...#elif __GNUC__
...#else
# error "Missing feature-test macro for 32/64-bit on this compiler."
?fuente
size_t
es lo suficientemente grande como para contener el tamaño de cualquier objeto asignado en el sistema. Por lo general, es lo que quieres saber al compilar condicionalmente. Si no es lo que desea, puede usar este fragmento con otro tipo en lugar desize_t
. Por ejemplo, podría servoid*
.Desafortunadamente, en un entorno de plataforma cruzada, compilador cruzado, no existe un método confiable único para hacer esto puramente en tiempo de compilación.
Por lo tanto, el único método confiable es combinar 3 verificaciones simples :
Comprobación simple 1/3: configuración del tiempo de compilación
Elija cualquier método para establecer la variable #define requerida. Sugiero el método de @JaredPar:
Verificación simple 2/3: Verificación de tiempo de ejecución
En main (), verifique dos veces si sizeof () tiene sentido:
Comprobación simple 3/3: comprobación robusta del tiempo de compilación
La regla general es "cada #definir debe terminar en un #else que genera un error".
Actualizar 2017-01-17
Comentario de
@AI.G
:Apéndice A
Incidentalmente, las reglas anteriores se pueden adaptar para hacer que toda su base de código sea más confiable:
La razón por la que esto funciona bien es que te obliga a pensar en cada caso por adelantado, y no confiar en la lógica (a veces defectuosa) en la parte "else" para ejecutar el código correcto.
Utilicé esta técnica (entre muchas otras) para escribir un proyecto de 30,000 líneas que funcionó perfectamente desde el día en que se implementó por primera vez en producción (eso fue hace 12 meses).
fuente
sizeof(void*)
¿Se resuelve en tiempo de compilación o en tiempo de ejecución? si es en tiempo de compilación, entonces en tiempo de ejecución la verificación siempre seráif(8!=8){...}
.static_assert(sizeof(void*) == 4);
. Ahora todo está hecho en tiempo de compilación :)static_assert(sizeof(void*) * CHAR_BIT == 32)
es más expresivo y técnicamente correcto (aunque no conozco ninguna arquitectura donde los bytes tengan una cantidad diferente de bits que 8)Debería poder usar las macros definidas en
stdint.h
. En particular,INTPTR_MAX
es exactamente el valor que necesita.Algunas versiones (¿todas?) Del compilador de Microsoft no vienen con
stdint.h
. No estoy seguro de por qué, ya que es un archivo estándar. Aquí hay una versión que puede usar:http://msinttypes.googlecode.com/svn/trunk/stdint.hfuente
<stdint.h>
y<cstdint>
. En cuanto al estado actual de las cosas, la biblioteca VC ++ se origina en Dinkumware (todavía lo hace, TR1 también se tomó de allí), pero por lo que recuerdo leer en VCBlog, se somete a una refactorización bastante significativa para compilar limpiamente/clr
, trabajar con todos los MSVC tipos no estándar como__int64
, etc., por lo que no es tan simple como tomarlo y ponerlo en la próxima versión del compilador.Eso no funcionará en Windows para empezar. Los largos y las entradas son 32 bits, ya sea que esté compilando para ventanas de 32 bits o 64 bits. Creo que verificar si el tamaño de un puntero es de 8 bytes es probablemente una ruta más confiable.
fuente
sizeof(void*) == 8 ? Do64Bit() : Do32Bit();
. Eso aún podría dejar una función no utilizada en el binario, pero la expresión probablemente se compila solo con una llamada a la función "correcta".template<int> struct Thing; template<> struct Thing<4> { typedef uint32_t type; }; template<> struct Thing<8> { typedef uint64_t type; }; typedef Thing<sizeof(void*)>::type thingtype;
Podrías hacer esto:
fuente
fuente
"Compilado en 64 bits" no está bien definido en C ++.
C ++ establece solo límites inferiores para tamaños como int, long y
void *
. No hay garantía de que int sea de 64 bits, incluso cuando se compila para una plataforma de 64 bits. El modelo permite, por ejemplo, 23 bitint
sysizeof(int *) != sizeof(char *)
Existen diferentes modelos de programación para plataformas de 64 bits.
Su mejor apuesta es una prueba específica de la plataforma. Su segunda mejor decisión portátil debe ser más específica en lo que es 64 bits.
fuente
Su enfoque no estaba muy lejos, pero solo está verificando si son del mismo tamaño
long
y siint
son del mismo tamaño. Teóricamente, ambos podrían ser de 64 bits, en cuyo caso su verificación fallaría, suponiendo que ambos sean de 32 bits. Aquí hay una verificación que realmente verifica el tamaño de los tipos en sí, no su tamaño relativo:En principio, puede hacer esto para cualquier tipo para el que tenga una macro definida por el sistema con el valor máximo.
Tenga en cuenta que el estándar requiere
long long
al menos 64 bits, incluso en sistemas de 32 bits.fuente
#include <limits.h>
algún lugar antes de sus#if
pruebas.La gente ya sugirió métodos que intentarán determinar si el programa se está compilando
32-bit
o64-bit
.Y quiero agregar que puedes usar la función c ++ 11
static_assert
para asegurarse de que la arquitectura es lo que usted piensa que es ("para relajarse").Entonces, en el lugar donde define las macros:
fuente
static_assert(sizeof(void*) * CHAR_BIT == 32)
es más expresivo y técnicamente correcto (aunque no conozco ninguna arquitectura donde los bytes tengan una cantidad diferente de bits que 8)El siguiente código funciona bien para la mayoría de los entornos actuales:
fuente
_WIN64
requiere que ya haya incluido<windows.h>
. Con Visual C ++, es mejor utilizar el built-in define compilador:_M_IX86
,_M_X64
,_M_ARM
,_M_ARM64
, etc.__ppc64__
,__powerpc64__
y_ARCH_PPC64
. Eso también atrapa a AIX y otras plataformas.Si puede usar configuraciones de proyecto en todos sus entornos, eso facilitaría la definición de un símbolo de 64 y 32 bits. Entonces tendrías configuraciones de proyecto como esta:
Depuración de
32 bits Versión de 32 bits Versión de
64 bits Depuración de
64 bits
EDITAR: Estas son configuraciones genéricas, no configuraciones dirigidas. Llámalos como quieras.
Si no puedes hacer eso, me gusta la idea de Jared.
fuente
Colocaría fuentes de 32 bits y 64 bits en diferentes archivos y luego seleccionaría los archivos fuente apropiados usando el sistema de compilación.
fuente
-DBUILD_64BIT
. A menudo, ciertas cosas son muy similares a 32 y 64 bits, por lo que tenerlo en el mismo archivo puede ser bastante práctico.Tomando prestado de la excelente respuesta anterior de Contango y combinándolo con " Mejores macros, mejores banderas " de Fluent C ++, puede hacer:
Entonces puedes usarlo como:
O usando la macro adicional que agregué:
fuente
Estoy agregando esta respuesta como un caso de uso y un ejemplo completo para la verificación de tiempo de ejecución descrita en otra respuesta .
Este es el enfoque que he estado adoptando para transmitir al usuario final si el programa se compiló como 64 bits o 32 bits (u otro, para el caso):
version.h
test.cc
Compilar y probar
fuente