Determining 32 vs 64 bit in C++

匿名 (未验证) 提交于 2019-12-03 08:42:37

问题:

I'm looking for a way to reliably determine whether C++ code is being compiled in 32 vs 64 bit. We've come up with what we think is a reasonable solution using macros, but was curious to know if people could think of cases where this might fail or if there is a better way to do this. Please note we are trying to do this in a cross-platform, multiple compiler environment.

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

Thanks.

回答1:

Unfortunately there is no cross platform macro which defines 32 / 64 bit across the major compilers. I've found the most effective way to do this is the following.

First I pick my own representation. I prefer ENVIRONMENT64 / ENVIRONMENT32. Then I find out what all of the major compilers use for determining if it's a 64 bit environment or not and use that to set my variables.

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

Another easier route is to simply set these variables from the compiler command line.



回答2:

template void DoMyOperationHelper();  template void DoMyOperationHelper()  {   // do 32-bits operations }  template void DoMyOperationHelper()  {   // do 64-bits operations }  // helper function just to hide clumsy syntax inline void DoMyOperation() { DoMyOperationHelper(); }  int main() {   // appropriate function will be selected at compile time    DoMyOperation();     return 0; } 


回答3:

Unfortunately, in a cross platform, cross compiler environment, there is no single reliable method to do this purely at compile time.

  • Both _WIN32 and _WIN64 can sometimes both be undefined, if the project settings are flawed or corrupted (particularly on Visual Studio 2008 SP1).
  • A project labelled "Win32" could be set to 64-bit, due to a project configuration error.
  • On Visual Studio 2008 SP1, sometimes the intellisense does not grey out the correct parts of the code, according to the current #define. This makes it difficult to see exactly which #define is being used at compile time.

Therefore, the only reliable method is to combine 3 simple checks:

  • 1) Compile time setting, and;
  • 2) Runtime check, and;
  • 3) Robust compile time checking.

Simple check 1/3: Compile time setting

Choose any method to set the required #define variable. I suggest the method from @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 

Simple check 2/3: Runtime check

In main(), double check to see if sizeof() makes sense:

#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 

Simple check 3/3: Robust compile time checking

The general rule is "every #define must end in a #else which generates an error".

#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 

Update 2017-01-17

Comment from @AI.G:

4 years later (don't know if it was possible before) you can convert the run-time check to compile-time one using static assert: static_assert(sizeof(void*) == 4);. Now it's all done at compile time :)

Appendix A

Incidentially, the rules above can be adapted to make your entire codebase more reliable:

  • Every if() statement ends in an "else" which generates a warning or error.
  • Every switch() statement ends in a "default:" which generates a warning or error.

The reason why this works well is that it forces you to think of every single case in advance, and not rely on (sometimes flawed) logic in the "else" part to execute the correct code.

I used this technique (among many others) to write a 30,000 line project that worked flawlessly from the day it was first deployed into production (that was 12 months ago).



回答4:

You should be able to use the macros defined in stdint.h. In particular INTPTR_MAX is exactly the value you need.

#include  #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 

Some (all?) versions of Microsoft's compiler don't come with stdint.h. Not sure why, since it's a standard file. Here's a version you can use: http://msinttypes.googlecode.com/svn/trunk/stdint.h



回答5:

That won't work on Windows for a start. Longs and ints are both 32 bits whether you're compiling for 32 bit or 64 bit windows. I would think checking if the size of a pointer is 8 bytes is probably a more reliable route.



回答6:

You could do this:

#if __WORDSIZE == 64 char *size = "64bits"; #else char *size = "32bits"; #endif 


回答7:

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 


回答8:

"Compiled in 64 bit" is not well defined in C++.

C++ sets only lower limits for sizes such as int, long and void *. There is no guarantee that int is 64 bit even when compiled for a 64 bit platform. The model allows for e.g. 23 bit ints and sizeof(int *) != sizeof(char *)

There are different programming models for 64 bit platforms.

Your best bet is a platform specific test. Your second best, portable decision must be more specific in what is 64 bit.



回答9:

People already suggested methods that will try to determine if the program is being compiled in 32-bit or 64-bit.

And I want to add that you can use the c++11 feature static_assert to make sure that the architecture is what you think it is ("to relax").

So in the place where you define the 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 


回答10:

I'd place 32-bit and 64-bit sources in different files and then select appropriate source files using the build system.



回答11:

Your approach was not too far off, but you are only checking whether long and int are of the same size. Theoretically, they could both be 64 bits, in which case your check would fail, assuming both to be 32 bits. Here is a check that actually checks the size of the types themselves, not their relative size:

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

In principle, you can do this for any type for which you have a system defined macro with the maximal value.

Note, that the standard requires long long to be at least 64 bits even on 32 bit systems.



回答12:

Below code works fine for most current environments:

  #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 


回答13:

If you can use project configurations in all your environments, that would make defining a 64- and 32-bit symbol easy. So you'd have project configurations like this:

32-bit Debug
32-bit Release
64-bit Debug
64-bit Release

EDIT: These are generic configurations, not targetted configurations. Call them whatever you want.

If you can't do that, I like Jared's idea.



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!