C ++에서 32 대 64 비트를 결정합니다
-
19-09-2019 - |
문제
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]