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.
- Tanto _WIN32 y _WIN64 pueden a veces tanto indefinidos, si la configuración del proyecto son defectuosos o dañados (particularmente en Visual Studio 2008 SP1).
- Un proyecto etiquetado como "Win32" podría establecerse en 64 bits, debido a un error de configuración del proyecto.
- En Visual Studio 2008 SP1, a veces el intellisense no atenúa las partes correctas del código, de acuerdo con el #define actual. Esto hace que sea difícil ver exactamente qué #define se está utilizando en tiempo de compilación.
Por lo tanto, el único método confiable es combinar 3 verificaciones simples :
- 1) Configuración del tiempo de compilación , y;
- 2) Verificación de tiempo de ejecución , y;
- 3) Comprobación robusta del tiempo de compilación .
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:
// 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
Verificación simple 2/3: Verificación de tiempo de ejecución
En main (), verifique dos veces 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
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".
#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
Actualizar 2017-01-17
Comentario de @AI.G
:
4 años después (no sé si era posible antes) puede convertir la verificación en tiempo de ejecución en una en tiempo de compilación utilizando la aserción estática: static_assert (sizeof (void *) == 4) ;. Ahora todo está hecho en tiempo de compilación :)
Apéndice A
Incidentalmente, las reglas anteriores se pueden adaptar para hacer que toda su base de código sea más confiable:
- Cada instrucción if () termina en un "else" que genera una advertencia o error.
- Cada instrucción switch () termina en un "valor predeterminado:" que genera una advertencia o error.
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).