Infelizmente, em um ambiente de plataforma cruzada e compilador cruzado, não existe um método confiável único para fazer isso exclusivamente em tempo de compilação.
- Ambos _WIN32 e _WIN64 às vezes pode tanto ser indefinido, se as configurações do projeto são falhos ou corrompido (particularmente no Visual Studio 2008 SP1).
- Um projeto chamado "Win32" pode ser definido como 64 bits, devido a um erro de configuração do projeto.
- No Visual Studio 2008 SP1, às vezes o intellisense não esmaece as partes corretas do código, de acordo com o atual #define. Isso dificulta ver exatamente qual #define está sendo usado em tempo de compilação.
Portanto, o único método confiável é combinar 3 verificações simples :
- 1) Configuração do tempo de compilação , e;
- 2) verificação de tempo de execução e;
- 3) Verificação robusta do tempo de compilação .
Verificação simples 1/3: configuração do tempo de compilação
Escolha qualquer método para definir a variável #define necessária. Sugiro o 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
Verificação simples 2/3: verificação de tempo de execução
Em main (), verifique novamente se sizeof () faz 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
Verificação simples 3/3: verificação robusta do tempo de compilação
A regra geral é "todo #define deve terminar em um #else que gera um erro".
#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
Atualização 2017-01-17
Comentário de @AI.G
:
4 anos depois (não sei se era possível antes), você pode converter a verificação em tempo de execução para uma em tempo de compilação usando a afirmação estática: static_assert (sizeof (void *) == 4) ;. Agora tudo é feito em tempo de compilação :)
Apêndice A
Incidencialmente, as regras acima podem ser adaptadas para tornar toda a sua base de código mais confiável:
- Cada instrução if () termina em um "else" que gera um aviso ou erro.
- Cada instrução switch () termina com um "padrão:" que gera um aviso ou erro.
A razão pela qual isso funciona bem é que obriga você a pensar em todos os casos com antecedência e a não confiar na lógica (às vezes falha) da parte "else" para executar o código correto.
Usei essa técnica (entre muitas outras) para escrever um projeto de 30.000 linhas que funcionou perfeitamente desde o primeiro dia em que foi implantado na produção (há 12 meses).