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

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

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

谢谢。

有帮助吗?

解决方案

不幸的是没有跨平台宏限定横跨主要编译器六十四分之三十二位。我发现这样做是下面的最有效的方法。

首先,我把我自己的代表。我更喜欢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

另一个更容易的途径是简单地设置为从编译器命令行这些变量。

其他提示

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,有时智能感知不会使代码的正确部分变灰。这使得很难在编译时准确地看出正在使用哪个#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:”结尾,这会生成警告或错误。

这种方法之所以有效,是因为它迫使您提前考虑每种情况,而不是依赖“else”部分中的(有时是有缺陷的)逻辑来执行正确的代码。

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

这不会一开始工作在Windows上。长材和整数都是32位,无论您是在编译的32位或64位Windows。我想检查是否指针的大小是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,长和void *只有下限。有没有保证,int是64位,甚至编译用于64位平台的时候。该模型允许例如23个ints和sizeof(int *) != sizeof(char *)

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

您最好的选择是特定于平台的测试。你的第二个最好的,便携的决定必须在更具体的什么的是64位。

您的做法是不是太离谱,但你只检查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位。

人们已经建议的方法,将尝试确定程序在32-bit64-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]
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top