在C++中确定32对64位

Joe*_*ery 127 c++ conditional-compilation 32bit-64bit

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

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

#ifdef IS64BIT
DoMy64BitOperation()
#else
DoMy32BitOperation()
#endif
Run Code Online (Sandbox Code Playgroud)

谢谢.

Kir*_*sky 99

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;
}
Run Code Online (Sandbox Code Playgroud)

  • @Jesper,然后你会在上面的示例中得到链接错误.或者你可以为这种情况实现DoMyOperation (16认同)
  • 标准说`size_t`的大小足以容纳系统中任何已分配对象的大小.通常,这是您在条件编译时想要了解的内容.如果它不是您想要的,您可以将此片段与其他类型而不是"size_t"一起使用.例如,它可能是`void*`. (6认同)
  • 如果size_t既不是4也不是8,会发生什么? (2认同)
  • 小心使用size_t.例如,您可能遇到与指针大小不对应的问题(例如,在具有多个指针大小的平台上). (2认同)

Jar*_*Par 96

不幸的是,没有跨平台宏在主要编译器中定义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
Run Code Online (Sandbox Code Playgroud)

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

  • @Rom,肯定超过2个编译器和架构.这只是一个如何解决这个问题的样本,而不是一个完整的解决方案. (14认同)
  • 我认为你应该使用"#if defined(_WIN32_)|| defined(_WIN64)"等 (7认同)
  • 好吧,除了GCC和VS之外还有其他编译器.例如,QNX和GHS会浮现在脑海中(尽管我怀疑QNX对GCC有类似的构建时定义).您还忘记了GCC检查中的MIPS64和IA64架构 (3认同)
  • `#if _WIN32 || _WIN64` ...`#elif __GNUC__` ...`#else``#error"在这个编译器上缺少32/64位的功能测试宏."`? (3认同)
  • 我说"通常"."理想情况下"可能更为现实. (2认同)

Con*_*ngo 43

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

  • 如果项目设置存在缺陷或损坏(特别是在Visual Studio 2008 SP1上),_WIN32和_WIN64有时可能未定义.
  • 由于项目配置错误,标记为"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
Run Code Online (Sandbox Code Playgroud)

简单检查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
Run Code Online (Sandbox Code Playgroud)

简单检查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
Run Code Online (Sandbox Code Playgroud)

更新2017-01-17

评论来自@AI.G:

4年后(不知道以前是否可能)你可以使用static assert将运行时检查转换为编译时检查:static_assert(sizeof(void*)== 4);. 现在它都是在编译时完成的:)

附录A.

从本质上讲,上述规则可以进行调整,使您的整个代码库更加可靠:

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

这种方法效果很好的原因在于它会强制您提前考虑每一个案例,而不是依赖于"else"部分中的(有时是有缺陷的)逻辑来执行正确的代码.

我使用这种技术(以及许多其他技术)编写了一个30,000行项目,从最初部署到生产的那一天起就完美无缺(那是12个月前).

  • 4年后(不知道以前是否可能)你可以使用静态断言将运行时检查转换为编译时:`static_assert(sizeof(void*)== 4);`.现在它都是在编译时完成的:) (3认同)

ale*_*gle 28

您应该能够使用中定义的宏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
Run Code Online (Sandbox Code Playgroud)

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

  • 为什么没有针对Microsoft的stdint.h?因为它是在C99标准中引入的,而且微软似乎对实现C99中最简单的东西有着积极的厌恶.即使是不需要编译器更改的简单库.甚至是编译C++时已经完成的东西(比如语句后的声明).我知道它需要测试等等,但我也知道MS从Dinkumware/Plauger获得(或曾经获得)其库的一大部分库,Dinkumware有多年的C99库. (4认同)
  • VC++ 2010(beta 1,无论如何)有`<stdint.h>`和`<cstdint>`.至于目前的状态 - VC++库来自Dinkumware(仍然可以 - 从那里也取得了TR1),但是从我记得在VCBlog上读到的,它经历了一个相当重要的重构,用`/ clr`干净地编译,使用所有MSVC非标准类型,如`__int64`,等等 - 这就是为什么它不像只是把它带入下一个编译器版本那么简单. (2认同)
  • 这使我得到了正确的答案,但是我认为您应该将其与UINT64_MAX而不是INT64_MAX进行比较。我用SIZE_MAX == UINT64_MAX-可能一样 (2认同)
  • @ArnoDuvenhage:“intptr_t”保证是有符号类型,所以这个答案是正确的。你的方法也会起作用,是的,我通常会选择无符号类型,因为如果我要对它们做任何棘手的事情,我认为指针是无符号整数(除了重做符号扩展来制作规范的 x86-64 指针)在将高位用于其他用途之后)。 (2认同)

mat*_*ort 15

这在Windows上不起作用.无论您是编译32位还是64位窗口,长整数和整数都是32位.我认为检查指针的大小是否是8字节可能是一个更可靠的路由.

  • 问题还没有(还)表示它*需要在预处理器时间完成.许多/大多数具有优化功能的编译器都会在消除死代码方面做得不错,即使你用"sizeof(void*)== 8"之类的测试"将其保留到运行时间"?Do64Bit():Do32Bit();`.这仍然可以在二进制文件中留下一个未使用的函数,但表达式可能只是为了调用"右"函数而编译. (3认同)
  • 不幸的是,在#if指令中禁止使用sizeof(如果你认为它预处理器无法分辨) (2认同)
  • @onebyone 解决了函数调用的问题,但是如果我想根据平台声明一个不同类型的变量,那需要在预处理器中完成,除非您想声明多个变量并基于 if 语句使用它们(如果不使用它们也会被优化,但在代码中不会很令人愉快) (2认同)

小智 8

你可以这样做:

#if __WORDSIZE == 64
char *size = "64bits";
#else
char *size = "32bits";
#endif
Run Code Online (Sandbox Code Playgroud)

  • 在 64 位机器上的 C 和 C 派生语言的许多编程环境中,“int”变量仍然是 32 位宽,但长整型和指针是 64 位宽。这些被描述为具有 LP64 数据模型。http://www.unix.org/version2/whatsnew/lp64_wp.html (2认同)

小智 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
Run Code Online (Sandbox Code Playgroud)

  • 此代码不正确.在64位上,定义了_WIN32和_WIN64.如果你把它转过来(首先检查_WIN64),它当然是有效的. (6认同)

Ale*_*rth 6

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

  #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
Run Code Online (Sandbox Code Playgroud)

  • 请注意,``_WIN64`` 要求您已经包含``&lt;windows.h&gt;``。对于 Visual C++,最好使用内置编译器定义:``_M_IX86``、``_M_X64``、``_M_ARM``、``_M_ARM64`` 等。 (6认同)