在C ++中确定32对64位

时间:2009-10-01 18:17:14

标签: c++ 32bit-64bit conditional-compilation

我正在寻找一种方法来可靠地确定C ++代码是在32位还是64位编译。我们已经提出了我们认为使用宏的合理解决方案,但很想知道人们是否可以想到这可能会失败的情况,或者是否有更好的方法来做到这一点。请注意,我们正在尝试在跨平台的多编译器环境中执行此操作。

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

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

感谢。

15 个答案:

答案 0 :(得分:95)

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

答案 1 :(得分:94)

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

首先,我选择自己的代表。我更喜欢ENVIRONMENT64 / ENVIRONMENT32。然后我找出所有主要编译器使用什么来确定它是否是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

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

答案 2 :(得分:40)

不幸的是,在跨平台的交叉编译环境中,没有一种可靠的方法可以在编译时完全实现这一点。

  • 如果项目设置存在缺陷或损坏(特别是在Visual Studio 2008 SP1上),_WIN32和_WIN64有时两者都未定义。
  • 由于项目配置错误,标记为“Win32”的项目可能设置为64位。
  • 在Visual Studio 2008 SP1上,根据当前的#define,有时智能感知不会使代码的正确部分变灰。这使得很难确切地看到在编译时使用了哪个#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结尾”。

#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年后(不知道以前是否可能)你可以转换   使用静态断言对运行时检查编译时间:   static_assert(sizeof(void *)== 4);。现在,这一切都在编译时完成   :)

附录A

从根本上说,上述规则可以进行调整,以使整个代码库更加可靠:

  • 每个if()语句都以“else”结尾,生成警告或错误。
  • 每个switch()语句都以“default:”结尾,这会生成警告或错误。

这种方法运作良好的原因在于它会强制您提前考虑每一个案例,而不是依赖“其他”部分中的(有时是有缺陷的)逻辑来执行正确的代码。

我使用这种技术(以及许多其他技术)编写了一个30,000行项目,该项目从首次投入生产之日起就完美无缺(即12个月前)。

答案 3 :(得分:24)

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

答案 4 :(得分:15)

这不适用于Windows的开始。无论您是编译32位还是64位窗口,长整数和整数都是32位。我会考虑检查一个指针的大小是否是一个更可靠的路径。

答案 5 :(得分:8)

你可以这样做:

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

答案 6 :(得分: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

答案 7 :(得分:4)

“以64位编译”在C ++中没有很好地定义。

C ++仅设置int,long和void *等大小的下限。即使在为64位平台编译时,也无法保证int为64位。该模型允许例如23位intsizeof(int *) != sizeof(char *)

64位平台有不同的programming models

您最好的选择是平台特定测试。您的第二个最佳便携式决策必须更明确 是64位。

答案 8 :(得分:3)

人们已经建议了一些方法,这些方法将尝试确定是在32-bit还是64-bit编译程序。

我想补充一点,您可以使用c ++ 11功能static_assert来确保架构符合您的想法(&#34;放松&#34;)。

所以在你定义宏的地方:

#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

答案 9 :(得分:2)

您的方法并不太远,但您只是检查longint的大小是否相同。从理论上讲,它们都可以是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

原则上,您可以为具有最大值的系统定义宏的任何类型执行此操作。

注意,即使在32位系统上,标准也要求long long至少为64位。

答案 10 :(得分:2)

以下代码适用于大多数当前环境:

/usr/local/bin/python

答案 11 :(得分:1)

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

32位调试
32位版本 64位调试
64位版本

编辑:这些是通用配置,而不是目标配置。无论你想要什么,都打电话给他们。

如果你不能这样做,我喜欢Jared的想法。

答案 12 :(得分:1)

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

答案 13 :(得分:1)

借用Contangoexcellent answer above并将其与Fluent C ++中的“ Better Macros, Better Flags”组合,您可以执行以下操作:

// Macro for checking bitness (safer macros borrowed from 
// https://www.fluentcpp.com/2019/05/28/better-macros-better-flags/)
#define MYPROJ_IS_BITNESS( X ) MYPROJ_IS_BITNESS_PRIVATE_DEFINITION_##X()

// Bitness checks borrowed from https://stackoverflow.com/a/12338526/201787
#if _WIN64 || ( __GNUC__ && __x86_64__ )
#    define MYPROJ_IS_BITNESS_PRIVATE_DEFINITION_64() 1
#    define MYPROJ_IS_BITNESS_PRIVATE_DEFINITION_32() 0
#    define MYPROJ_IF_64_BIT_ELSE( x64, x86 ) (x64)
    static_assert( sizeof( void* ) == 8, "Pointer size is unexpected for this bitness" );
#elif _WIN32 || __GNUC__
#    define MYPROJ_IS_BITNESS_PRIVATE_DEFINITION_64() 0
#    define MYPROJ_IS_BITNESS_PRIVATE_DEFINITION_32() 1
#    define MYPROJ_IF_64_BIT_ELSE( x64, x86 ) (x86)
    static_assert( sizeof( void* ) == 4, "Pointer size is unexpected for this bitness" );
#else
#    error "Unknown bitness!"
#endif

然后您可以像使用它一样

#if MYPROJ_IS_BITNESS( 64 )
    DoMy64BitOperation()
#else
    DoMy32BitOperation()
#endif

或使用我添加的额外宏:

MYPROJ_IF_64_BIT_ELSE( DoMy64BitOperation(), DoMy32BitOperation() );

答案 14 :(得分:0)

我正在将此答案作为用例和another answer中所述的运行时检查的完整示例。

无论程序是编译为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]