在c++中确定32和64位。

时间:2021-02-12 12:05:23

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.

我正在寻找一种可靠的方法来确定c++代码是否在32和64位之间编译。我们已经提出了一个使用宏的合理的解决方案,但是很想知道人们是否会想到可能会失败的情况,或者是否有更好的方法来解决这个问题。请注意,我们正试图在一个跨平台、多个编译器环境中进行此操作。

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

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

Thanks.

谢谢。

13 个解决方案

#1


88  

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.

不幸的是,没有跨平台宏在主要编译器上定义32 / 64位。我发现最有效的方法如下。

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.

首先我选择自己的代表。我喜欢环境保护。然后,我发现所有主要的编译器使用什么来确定它是否为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

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

另一个更简单的方法是简单地从编译器命令行设置这些变量。

#2


91  

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

#3


38  

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).
  • 如果项目设置有缺陷或损坏(特别是在Visual Studio 2008 SP1中),那么_WIN32和_WIN64有时都是未定义的。
  • A project labelled "Win32" could be set to 64-bit, due to a project configuration error.
  • 由于项目配置错误,一个标记为“Win32”的项目可以被设置为64位。
  • 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.
  • 在Visual Studio 2008 SP1中,根据当前的#define,有时智能感知不排除代码的正确部分。这使得在编译时很难确切地看到哪个#define被使用。

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

因此,唯一可靠的方法是结合3个简单的检查:

  • 1) Compile time setting, and;
  • 1)编译时间设置;
  • 2) Runtime check, and;
  • 2)运行时检查,;
  • 3) Robust compile time checking.
  • 3)健壮的编译时间检查。

Simple check 1/3: Compile time setting

Choose any method to set the required #define variable. I suggest the method from @JaredPar:

选择任何方法来设置所需的#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

Simple check 2/3: Runtime check

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

在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

Simple check 3/3: Robust compile time checking

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

一般规则是“每个#define必须以#else结尾,否则会产生错误”。

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

从@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 :)

4年后(不知道是否有可能),您可以将运行时检查转换为编译时使用静态断言:static_assert(sizeof(void*) == 4);现在这些都是在编译时完成的:)

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.
  • 每个if()语句以“else”结尾,生成警告或错误。
  • Every switch() statement ends in a "default:" which generates a warning or error.
  • 每个switch()语句以“default:”结尾,生成警告或错误。

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.

这样做的原因是,它迫使您提前考虑每一个案例,而不是依赖(有时是有缺陷的)“else”部分的逻辑来执行正确的代码。

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).

我使用这种技术(在其他许多方面)编写了一个3万行的项目,该项目从第一次部署到生产(那是12个月前)的时候完美地工作了。

#4


17  

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

您应该能够使用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

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

微软编译器的一些(所有?)版本都不支持stdint.h。不知道为什么,因为它是一个标准文件。这里有一个您可以使用的版本:http://msinttypes.googlecode.com/svn/trunk/stdint.h。

#5


15  

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.

这在Windows上是行不通的。无论你是编译32位还是64位windows, Longs和ints都是32位。我认为检查指针的大小是否为8字节可能是更可靠的方法。

#6


8  

You could do this:

你可以这样做:

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

#7


6  

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


4  

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

“64位编译”在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 *)

只对int、long和void *的大小设置较低的限制。没有保证即使编译了64位的平台,int也是64位。该模型允许使用23位ints和sizeof(int *) != sizeof(char *)

There are different programming models for 64 bit platforms.

64位平台有不同的编程模型。

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

你最好的选择是一个平台特定的测试。你的第二个最好的,可移植的决定必须更具体的在64位。

#9


3  

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

人们已经提出了一些方法,试图确定该程序是在32位还是64位编译的。

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").

我还想补充一点,您可以使用c++11特性static_assert来确保架构是您认为的(“放松”)。

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


2  

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:

您的方法不太离谱,但您只检查长和整数是否相同。理论上,它们都可以是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

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.

注意,标准要求在32位系统上至少需要64位。

#11


2  

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

#12


1  

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:

如果您可以在您的所有环境中使用项目配置,那么就可以轻松定义64位和32位的符号。你会有这样的项目配置:

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

32位调试32位释放64位的64位版本。

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

编辑:这些是通用配置,而不是目标配置。你想怎么称呼都行。

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

如果你不能这么做,我喜欢杰瑞德的主意。

#13


1  

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

我在不同的文件中放置32位和64位源,然后使用构建系统选择合适的源文件。

#1


88  

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.

不幸的是,没有跨平台宏在主要编译器上定义32 / 64位。我发现最有效的方法如下。

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.

首先我选择自己的代表。我喜欢环境保护。然后,我发现所有主要的编译器使用什么来确定它是否为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

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

另一个更简单的方法是简单地从编译器命令行设置这些变量。

#2


91  

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

#3


38  

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).
  • 如果项目设置有缺陷或损坏(特别是在Visual Studio 2008 SP1中),那么_WIN32和_WIN64有时都是未定义的。
  • A project labelled "Win32" could be set to 64-bit, due to a project configuration error.
  • 由于项目配置错误,一个标记为“Win32”的项目可以被设置为64位。
  • 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.
  • 在Visual Studio 2008 SP1中,根据当前的#define,有时智能感知不排除代码的正确部分。这使得在编译时很难确切地看到哪个#define被使用。

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

因此,唯一可靠的方法是结合3个简单的检查:

  • 1) Compile time setting, and;
  • 1)编译时间设置;
  • 2) Runtime check, and;
  • 2)运行时检查,;
  • 3) Robust compile time checking.
  • 3)健壮的编译时间检查。

Simple check 1/3: Compile time setting

Choose any method to set the required #define variable. I suggest the method from @JaredPar:

选择任何方法来设置所需的#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

Simple check 2/3: Runtime check

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

在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

Simple check 3/3: Robust compile time checking

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

一般规则是“每个#define必须以#else结尾,否则会产生错误”。

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

从@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 :)

4年后(不知道是否有可能),您可以将运行时检查转换为编译时使用静态断言:static_assert(sizeof(void*) == 4);现在这些都是在编译时完成的:)

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.
  • 每个if()语句以“else”结尾,生成警告或错误。
  • Every switch() statement ends in a "default:" which generates a warning or error.
  • 每个switch()语句以“default:”结尾,生成警告或错误。

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.

这样做的原因是,它迫使您提前考虑每一个案例,而不是依赖(有时是有缺陷的)“else”部分的逻辑来执行正确的代码。

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).

我使用这种技术(在其他许多方面)编写了一个3万行的项目,该项目从第一次部署到生产(那是12个月前)的时候完美地工作了。

#4


17  

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

您应该能够使用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

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

微软编译器的一些(所有?)版本都不支持stdint.h。不知道为什么,因为它是一个标准文件。这里有一个您可以使用的版本:http://msinttypes.googlecode.com/svn/trunk/stdint.h。

#5


15  

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.

这在Windows上是行不通的。无论你是编译32位还是64位windows, Longs和ints都是32位。我认为检查指针的大小是否为8字节可能是更可靠的方法。

#6


8  

You could do this:

你可以这样做:

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

#7


6  

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


4  

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

“64位编译”在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 *)

只对int、long和void *的大小设置较低的限制。没有保证即使编译了64位的平台,int也是64位。该模型允许使用23位ints和sizeof(int *) != sizeof(char *)

There are different programming models for 64 bit platforms.

64位平台有不同的编程模型。

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

你最好的选择是一个平台特定的测试。你的第二个最好的,可移植的决定必须更具体的在64位。

#9


3  

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

人们已经提出了一些方法,试图确定该程序是在32位还是64位编译的。

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").

我还想补充一点,您可以使用c++11特性static_assert来确保架构是您认为的(“放松”)。

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


2  

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:

您的方法不太离谱,但您只检查长和整数是否相同。理论上,它们都可以是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

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.

注意,标准要求在32位系统上至少需要64位。

#11


2  

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

#12


1  

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:

如果您可以在您的所有环境中使用项目配置,那么就可以轻松定义64位和32位的符号。你会有这样的项目配置:

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

32位调试32位释放64位的64位版本。

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

编辑:这些是通用配置,而不是目标配置。你想怎么称呼都行。

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

如果你不能这么做,我喜欢杰瑞德的主意。

#13


1  

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

我在不同的文件中放置32位和64位源,然后使用构建系统选择合适的源文件。