在 C++ 中确定 32 位与 64 位
-
19-09-2019 - |
题
我正在寻找一种方法来可靠地确定 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 个月前)之日起就完美运行。
您应该能够使用在 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
微软的编译器的部分(全部?)版本不附带stdint.h
。不知道为什么,因为它是一个标准的文件。这里是你可以使用一个版本: 的 http://msinttypes.googlecode.com/svn/trunk/stdint.h
这不会一开始工作在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个int
s和sizeof(int *) != sizeof(char *)
有不同编程模型的64个平台。
您最好的选择是特定于平台的测试。你的第二个最好的,便携的决定必须在更具体的什么的是64位。
您的做法是不是太离谱,但你只检查long
和int
是否相同大小的。从理论上讲,他们可以同时为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-bit
或64-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]