Pergunta

Eu estou procurando uma maneira de determinar de forma confiável se o código C ++ está sendo compilado em 32 vs 64 bit. Nós viemos acima com o que pensamos ser uma solução razoável usando macros, mas estava curioso para saber se as pessoas pudessem pensar em casos onde isso pode falhar ou se há uma maneira melhor de fazer isso. Por favor, note que estamos tentando fazer isso em um multi-plataforma, múltiplos ambiente compilador.

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

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

Graças.

Foi útil?

Solução

Infelizmente não há nenhuma macro de plataforma cruzada que define 32/64 bit através das principais compiladores. Eu encontrei a maneira mais eficaz de fazer isso é o seguinte.

Primeiro eu pegar minha própria representação. Eu prefiro ENVIRONMENT64 / ENVIRONMENT32. Então eu descobrir o que todos os principais compiladores usar para determinar se é um ambiente de 64 bits ou não e usar isso para definir meus variáveis.

// 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

Outra rota mais fácil é simplesmente definir essas variáveis ??a partir da linha de comando do compilador.

Outras dicas

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

Infelizmente, em uma plataforma cruzada, ambiente compilador cruzado, não existe um método único confiável para fazer isso puramente em tempo de compilação.

  • Ambos _WIN32 e _WIN64 pode, por vezes ambos ser indefinido, se as configurações do projeto são falhos ou corrompido (particularmente no Visual Studio 2008 SP1).
  • Um projeto rotulado de "Win32" poderia ser ajustado para 64 bits, devido a um erro de configuração do projeto.
  • No Visual Studio 2008 SP1, às vezes o intellisense não cinza para fora as peças corretas do código, segundo o #define atual. Isso torna difícil para ver exatamente quais #define está sendo usada no momento da compilação.

Portanto, o só é confiável método é combinar 3 verificações simples :

  • 1) configuração tempo de compilação , e;
  • 2) verificação de tempo de execução , e;
  • 3) compilação Robust tempo verificação .

seleção Simple 1/3: Ajuste tempo de compilação

Escolha qualquer método para set a variável #define necessário. Eu sugiro que 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

seleção Simple 2/3: Runtime verificar

Na verificação main (), o dobro para ver 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

seleção Simple 3/3: Robust verificação de tempo de compilação

A regra geral é "cada #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 mais tarde (não sei se era possível antes) você pode converter a verificação de tempo de execução para compilar-time um usando assert estática: static_assert (sizeof (void *) == 4) ;. Agora tudo é feito em tempo de compilação :)

Apêndice A

incidentially, as regras acima pode ser adaptado para fazer toda a sua base de código mais confiável:

  • Cada if () extremidades declaração em um "else" que gera um aviso ou erro.
  • Cada switch () extremidades declaração em um "default:" o que gera um aviso ou erro
  • .

A razão por que isso funciona bem é que ele força você a pensar em todos os casos com antecedência, e não depender de lógica (por vezes falho) na parte "else" para executar o código correto.

Eu usei esta técnica (entre muitos outros) para escrever um projeto de 30.000 linha que funcionou perfeitamente do dia em que foi implantado pela primeira vez em produção (que foi de 12 meses atrás).

Você deve ser capaz de usar as macros definidos no stdint.h . Em particular INTPTR_MAX é exatamente o valor que você precisa.

#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

Alguns (todos?) Versões de compilador do Microsoft não vêm com 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.h

Isso não vai funcionar no Windows para um começo. Longs e ints são ambos 32 bits se você está compilando para Windows de 32 bits ou 64 bits. Eu acho que verificar se o tamanho de um ponteiro é de 8 bytes é provavelmente uma rota mais confiável.

Você pode fazer isso:

#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

"compilado em 64 bits" não está bem definida em C ++.

conjuntos C ++ únicos limites mais baixos para os tamanhos, como int, long e void *. Não há garantia de que int é 64 bits, mesmo quando compilado para uma plataforma de 64 bits. O modelo permite, por exemplo, 23 ints bits e sizeof(int *) != sizeof(char *)

Existem diferentes modelos de programação para plataformas de 64 bits.

Sua melhor aposta é um teste de plataforma específica. Sua segunda melhor decisão, portátil deve ser mais específico em o é de 64 bits.

A sua abordagem não foi muito longe, mas você só estão verificando se long e int são do mesmo tamanho. Teoricamente, eles poderiam ser tanto 64 bits, caso em que o seu check falhariam, assumindo tanto para ser 32 bits. Aqui está um cheque que verifica efectivamente o tamanho dos tipos de si mesmos, não seu tamanho 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

Em princípio, você pode fazer isso por qualquer tipo para o qual você tem um macro definido sistema com o valor máximo.

Note, que a norma exige long long para ser pelo menos 64 bits, mesmo em sistemas de 32 bits.

As pessoas já métodos que tentarão determinar se o programa está sendo compilado em 32-bit ou 64-bit sugeriu.

E quero acrescentar que você pode usar o static_assert c ++ 11 recurso para se certificar de que a arquitetura é o que você pensa que é ( "para relaxar").

Assim, no lugar onde você define as 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

Abaixo código fina funciona para a maioria dos ambientes atuais:

  #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

Se você pode usar configurações do projeto em todos os seus ambientes, que faria a definição de um símbolo de 64 e 32 bits fácil. Então você teria configurações de projeto como este:

32-bit Debug
32-bit lançamento
64-bit Debug
64-bit lançamento

EDIT: Estes são configurações genéricas, não configurações direcionados. Chamá-los o que quiser.

Se você não pode fazer isso, eu como a idéia de Jared.

Eu coloque fontes de 32 bits e de 64 bits em diferentes arquivos e selecione os arquivos de origem apropriadas usando o sistema de compilação.

Eu estou adicionando esta resposta como um caso de uso e exemplo completa para o tempo de execução de verificação descrito no outra resposta .

Esta é a abordagem que eu tenho levado para o transporte para o usuário final se o programa foi compilado como de 64 bits ou de 32 bits (ou outro, para que o assunto):

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 e testar

g++ -g test.cc
./a.out
My App v0.09 [64-bit]
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top