문제

C ++ 코드가 32 대 64 비트로 컴파일되는지 여부를 안정적으로 결정할 수있는 방법을 찾고 있습니다. 우리는 매크로를 사용하는 합리적인 솔루션이라고 생각하는 것을 생각해 냈지만 사람들이 이것이 실패 할 수있는 경우 또는 더 나은 방법이 있는지 생각할 수 있는지 궁금했습니다. 크로스 플랫폼, 다중 컴파일러 환경 에서이 작업을 수행하려고합니다.

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

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

감사.

도움이 되었습니까?

해결책

불행히도 주요 컴파일러에서 32 / 64 비트를 정의하는 크로스 플랫폼 매크로가 없습니다. 가장 효과적인 방법은 다음과 같습니다.

먼저 나는 내 자신의 표현을 선택합니다. 환경 64 / 환경 32를 선호합니다. 그런 다음 모든 주요 컴파일러가 64 비트 환경인지 여부를 결정하고 변수를 설정하는 데 사용하는 데 무엇을 사용하는지 알아냅니다.

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

또 다른 더 쉬운 경로는 단순히 이러한 변수를 컴파일러 명령 줄에서 설정하는 것입니다.

다른 팁

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

불행히도, 크로스 플랫폼, 크로스 컴파일러 환경에서는 컴파일 시간에 순전히이를 수행 할 수있는 단일 신뢰할 수있는 방법이 없습니다.

  • _win32와 _win64는 때때로 할 수 있습니다 둘 다 프로젝트 설정에 결함이 있거나 손상된 경우 (특히 Visual Studio 2008 SP1).
  • 프로젝트 구성 오류로 인해 "Win32"라는 프로젝트를 64 비트로 설정할 수 있습니다.
  • Visual Studio 2008 SP1에서는 현재 #Define에 따르면 Intellisense가 코드의 올바른 부분을 회색으로 만들지 않습니다. 이로 인해 컴파일 시간에 어떤 #define이 사용되는지 정확히보기가 어렵습니다.

따라서, 신뢰할 수 있습니다 방법은 결합하는 것입니다 3 간단한 수표:

  • 1) 시간 설정을 컴파일하십시오, 그리고;
  • 2) 런타임 확인, 그리고;
  • 3) 강력한 컴파일 시간 점검.

간단한 점검 1/3 : 시간 설정을 컴파일하십시오

모든 방법을 선택하십시오 세트 필요한 #define 변수. @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

간단한 점검 2/3 : 런타임 확인

main ()에서는 sizeof ()가 의미가 있는지 확인하기 위해 이중 점검을합니다.

#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

간단한 점검 3/3 : 강력한 컴파일 시간 점검

일반적인 규칙은 "모든 #define은 #ELSE로 끝나야하는 모든 #Define이 오류를 생성해야합니다"입니다.

#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

업데이트 2017-01-17

댓글 @AI.G:

4 년 후 (이전에 가능했는지 알 수 없음) 런타임 검사를 정적 assert : static_assert (sizeof (void*) == 4)를 사용하여 런타임 검사를 컴파일 타임으로 변환 할 수 있습니다. 이제 모든 것이 컴파일 시간에 완료되었습니다 :)

부록

실시적으로, 위의 규칙은 전체 코드베이스를보다 신뢰할 수 있도록 조정할 수 있습니다.

  • 모든 if () 문은 경고 또는 오류를 생성하는 "else"로 끝납니다.
  • 모든 스위치 () 명령문은 "기본값 :"로 끝나며 경고 또는 오류가 발생합니다.

이것이 잘 작동하는 이유는 모든 단일 사례를 미리 생각하고 "다른"부분의 논리에 의존하지 않기 때문에 올바른 코드를 실행하기 때문입니다.

나는이 기술을 사용하여 (많은 것들 중에서도) 처음으로 생산에 배치 된 날부터 완벽하게 작동 한 30,000 라인 프로젝트를 작성했습니다 (12 개월 전).

정의 된 매크로를 사용할 수 있어야합니다. stdint.h. 특히 INTPTR_MAX 정확히 필요한 가치입니다.

#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

Microsoft 컴파일러의 일부 (모두?) 버전은 stdint.h. 왜 표준 파일이기 때문에 왜 그런지 잘 모르겠습니다. 다음은 사용할 수있는 버전입니다. http://msinttypes.googlecode.com/svn/trunk/stdint.h

그것은 시작하기 위해 Windows에서 작동하지 않습니다. Long과 Ints는 32 비트 또는 64 비트 창으로 컴파일하든 32 비트입니다. 포인터의 크기가 8 바이트인지 확인하는 것이 아마도 더 안정적인 경로 일 것입니다.

당신은 이것을 할 수 있습니다 :

#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

"64 비트로 컴파일"은 C ++에서 잘 정의되어 있지 않습니다.

C ++는 int, long 및와 같은 크기에 대해서만 하한을 설정합니다. void *. 64 비트 플랫폼에 대해 컴파일 된 경우에도 Int가 64 비트라는 것을 보장 할 수 없습니다. 이 모델은 예를 들어 23 비트를 허용합니다 int모래 sizeof(int *) != sizeof(char *)

다른 것이 있습니다 프로그래밍 모델 64 비트 플랫폼의 경우.

최선의 방법은 플랫폼 별 테스트입니다. 두 번째로 가장 좋은 휴대용 결정은 더 구체적이어야합니다. 무엇 64 비트입니다.

당신의 접근 방식은 그리 멀지 않았지만 당신은 long 그리고 int 크기가 같은 것입니다. 이론적으로, 그들은 둘 다 64 비트 일 수 있으며,이 경우 수표가 32 비트라고 가정하면 수표가 실패합니다. 다음은 상대적 크기가 아니라 유형의 크기를 실제로 확인하는 점검입니다.

#if ((UINT_MAX) == 0xffffffffu)
    #define INT_IS32BIT
#else
    #define INT_IS64BIT
#endif
#if ((ULONG_MAX) == 0xfffffffful)
    #define LONG_IS32BIT
#else
    #define LONG_IS64BIT
#endif

원칙적으로, 최대 값을 가진 시스템 정의 매크로가있는 모든 유형에 대해이 작업을 수행 할 수 있습니다.

표준에 필요합니다 long long 32 비트 시스템에서도 최소 64 비트가됩니다.

사람들은 이미 프로그램이 컴파일되는지 판단하려는 방법을 제안했습니다. 32-bit 또는 64-bit.

C ++ 11 기능을 사용할 수 있다고 덧붙이고 싶습니다. static_assert 아키텍처가 당신이 생각하는 것인지 확인하기 위해 ( "긴장을 풀기").

그래서 당신이 매크로를 정의하는 장소에서 :

#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

아래 코드는 대부분의 현재 환경에서 잘 작동합니다.

  #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

모든 환경에서 프로젝트 구성을 사용할 수 있다면 64 및 32 비트 기호를 쉽게 정의 할 수 있습니다. 따라서 다음과 같은 프로젝트 구성이 있습니다.

32 비트 디버그
32 비트 릴리스
64 비트 디버그
64 비트 릴리스

편집 : 이들은 대상 구성이 아닌 일반적인 구성입니다. 원하는대로 전화하십시오.

당신이 그렇게 할 수 없다면, 나는 Jared의 아이디어를 좋아합니다.

32 비트 및 64 비트 소스를 다른 파일에 배치 한 다음 빌드 시스템을 사용하여 적절한 소스 파일을 선택합니다.

이 답변을 사용 케이스로 추가하고 다음에 설명 된 런타임 확인에 대한 완전한 예제입니다. 또 다른 대답.

이것은 프로그램이 64 비트 또는 32 비트 (또는 그 문제에 대해)로 컴파일되었는지 여부에 관계없이 최종 사용자에게 전달하기 위해 취한 접근법입니다.

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

컴파일 및 테스트

g++ -g test.cc
./a.out
My App v0.09 [64-bit]
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top