Eu estou procurando uma maneira de determinar com segurança se o código C ++ está sendo compilado em 32 vs 64 bits. Chegamos ao que pensamos ser uma solução razoável usando macros, mas estávamos curiosos para saber se as pessoas poderiam pensar em casos em que isso pode falhar ou se há uma maneira melhor de fazer isso. Observe que estamos tentando fazer isso em um ambiente compilador de múltiplas plataformas.
#if ((ULONG_MAX) == (UINT_MAX))
# define IS32BIT
#else
# define IS64BIT
#endif
#ifdef IS64BIT
DoMy64BitOperation()
#else
DoMy32BitOperation()
#endif
Obrigado.
c++
32bit-64bit
conditional-compilation
Joe Corkery
fonte
fonte
stdint.h
pode ser seu amigo ou pode ser necessário desenvolver alguns tipos de dados apropriados.Respostas:
Infelizmente, não há macro de plataforma cruzada que defina 32/64 bits nos principais compiladores. Eu descobri que a maneira mais eficaz de fazer isso é o seguinte.
Primeiro eu escolho minha própria representação. Prefiro AMBIENTE64 / AMBIENTE32. Depois, descubro o que todos os principais compiladores usam para determinar se é um ambiente de 64 bits ou não e o uso para definir minhas variáveis.
Outra rota mais fácil é simplesmente definir essas variáveis na linha de comando do compilador.
fonte
#if _WIN32 || _WIN64
...#elif __GNUC__
...#else
# error "Missing feature-test macro for 32/64-bit on this compiler."
?fonte
size_t
é grande o suficiente para armazenar o tamanho de qualquer objeto alocado no sistema. Geralmente é o que você deseja saber enquanto compila condicionalmente. Se não é o que você deseja, você pode usar esse snippet com outro tipo em vez desize_t
. Por exemplo, poderia servoid*
.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.
Portanto, o único método confiável é combinar 3 verificações simples :
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:
Verificação simples 2/3: verificação de tempo de execução
Em main (), verifique novamente se sizeof () faz sentido:
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".
Atualização 2017-01-17
Comentário de
@AI.G
:Apêndice A
Incidencialmente, as regras acima podem ser adaptadas para tornar toda a sua base de código mais confiável:
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).
fonte
sizeof(void*)
é resolvido em tempo de compilação ou tempo de execução? se estiver em tempo de compilação, em tempo de execução, a verificação sempre seráif(8!=8){...}
.static_assert(sizeof(void*) == 4);
. Agora tudo é feito em tempo de compilação :)static_assert(sizeof(void*) * CHAR_BIT == 32)
é mais expressiva e tecnicamente correta (embora eu não sei qualquer arquitetura onde bytes tem uma quantidade diferente de bits de 8)Você deve poder usar as macros definidas em
stdint.h
. Em particular,INTPTR_MAX
é exatamente o valor que você precisa.Algumas versões (todas?) Do compilador da Microsoft não são fornecidas
stdint.h
. Não sei por que, já que é um arquivo padrão. Aqui está uma versão que você pode usar:http://msinttypes.googlecode.com/svn/trunk/stdint.hfonte
<stdint.h>
e<cstdint>
. Quanto ao estado atual - a biblioteca VC ++ é originária do Dinkumware (ainda existe - o TR1 também foi retirado de lá), mas pelo que me lembro de ter lido no VCBlog, ele passa por uma refatoração bastante significativa para compilar corretamente/clr
, trabalhar com todos os MSVC tipos não-padrão como__int64
, e assim por diante - e é por isso que não é tão simples quanto levá-lo e colocá-lo na próxima versão do compilador.Isso não funcionará no Windows para começar. Longs e ints são ambos de 32 bits, esteja você compilando para janelas de 32 ou 64 bits. Eu acho que verificar se o tamanho de um ponteiro é 8 bytes é provavelmente uma rota mais confiável.
fonte
sizeof(void*) == 8 ? Do64Bit() : Do32Bit();
. Isso ainda pode deixar uma função não utilizada no binário, mas a expressão provavelmente é compilada apenas para uma chamada para a função "correta".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;
Você poderia fazer isso:
fonte
fonte
"Compilado em 64 bits" não está bem definido em C ++.
O C ++ define apenas limites inferiores para tamanhos como int, long e
void *
. Não há garantia de que int seja de 64 bits, mesmo quando compilado para uma plataforma de 64 bits. O modelo permite a por exemplo 23 bitsint
s esizeof(int *) != sizeof(char *)
Existem diferentes modelos de programação para plataformas de 64 bits.
Sua melhor aposta é um teste específico da plataforma. Sua segunda melhor decisão portátil deve ser mais específica no que é 64 bits.
fonte
Sua abordagem não foi muito distante, mas você está apenas verificando se
long
eint
tem o mesmo tamanho. Teoricamente, os dois poderiam ter 64 bits; nesse caso, sua verificação falharia, assumindo que ambos eram 32 bits. Aqui está uma verificação que realmente verifica o tamanho dos tipos em si, não o tamanho relativo:Em princípio, você pode fazer isso para qualquer tipo para o qual você tenha uma macro definida pelo sistema com o valor máximo.
Observe que o padrão exige
long long
pelo menos 64 bits, mesmo em sistemas de 32 bits.fonte
#include <limits.h>
algum lugar antes dos#if
testes.As pessoas já sugeriram métodos que tentarão determinar se o programa está sendo compilado em
32-bit
ou64-bit
.E quero acrescentar que você pode usar o recurso c ++ 11
static_assert
para garantir que a arquitetura seja o que você pensa que é ("relaxar").Portanto, no local em que você define as macros:
fonte
static_assert(sizeof(void*) * CHAR_BIT == 32)
é mais expressiva e tecnicamente correta (embora eu não sei qualquer arquitetura onde bytes tem uma quantidade diferente de bits de 8)O código abaixo funciona bem para a maioria dos ambientes atuais:
fonte
_WIN64
requer que você já tenha incluído<windows.h>
. Com o Visual C ++, é melhor usar o built-in define compilador:_M_IX86
,_M_X64
,_M_ARM
,_M_ARM64
, etc.__ppc64__
,__powerpc64__
e_ARCH_PPC64
. Isso também captura o AIX e outras plataformas.Se você puder usar as configurações do projeto em todos os seus ambientes, isso facilitaria a definição de um símbolo de 64 e 32 bits. Então você teria configurações de projeto como esta:
Depuração de
32 bits Liberação de
32 bits Depuração de 64 bits
64 bits Versão de 64 bits
EDIT: Estas são configurações genéricas, não configurações direcionadas. Ligue para eles como quiser.
Se você não pode fazer isso, eu gosto da ideia de Jared.
fonte
Colocaria fontes de 32 e 64 bits em arquivos diferentes e depois selecionaria os arquivos de origem apropriados usando o sistema de compilação.
fonte
-DBUILD_64BIT
. Freqüentemente, certas coisas são muito semelhantes às de 32 e 64 bits, portanto, tê-lo no mesmo arquivo pode ser bastante prático.Tomando emprestado a excelente resposta do Contango acima e combinando-a com " Melhores macros, melhores sinalizadores " do Fluent C ++, você pode:
Então você pode usá-lo como:
Ou usando a macro extra que eu adicionei:
fonte
Estou adicionando esta resposta como um caso de uso e exemplo completo para a verificação de tempo de execução descrita em outra resposta .
Esta é a abordagem que eu tenho adotado para transmitir ao usuário final se o programa foi compilado como 64 bits ou 32 bits (ou outro, nesse caso):
version.h
test.cc
Compilar e testar
fonte