在C ++中确定32位和64位
我正在寻找一种方法来可靠地确定C ++代码是否正在编译32位和64位。 我们已经提出了我们认为使用macros的合理解决scheme,但是很想知道人们是否可以考虑可能会失败的案例,或者是否有更好的方法来做到这一点。 请注意,我们正在尝试在跨平台的多编译器环境中执行此操作。
#if ((ULONG_MAX) == (UINT_MAX)) # define IS32BIT #else # define IS64BIT #endif #ifdef IS64BIT DoMy64BitOperation() #else DoMy32BitOperation() #endif
谢谢。
不幸的是没有跨主要编译器定义32/64位的跨平台macros。 我发现最有效的方法是这样的。
首先,我select我自己的代表。 我更喜欢ENVIRONMENT64 / ENVIRONMENT32。 然后我发现所有的主要编译器用来确定它是否是一个64位的环境,并用它来设置我的variables。
// 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
另一个简单的途径是简单地从编译器命令行设置这些variables。
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; }
不幸的是,在一个跨平台的交叉编译环境中,没有一个可靠的方法可以在编译时完成。
- 如果项目设置有缺陷或损坏(特别是在Visual Studio 2008 SP1上),_WIN32和_WIN64有时都可能是未定义的。
- 由于项目configuration错误,标记为“Win32”的项目可以设置为64位。
- 在Visual Studio 2008 SP1中,根据当前的#define,有时智能感知不会使代码的正确部分变灰。 这使得很难确切地看到在编译时使用了哪个#define。
因此, 唯一可靠的方法是结合3个简单的检查 :
- 1) 编译时间设置 ,
- 2) 运行时检查 ,并;
- 3) 强大的编译时间检查 。
简单检查1/3:编译时间设置
select任何方法来设置所需的#definevariables。 我build议@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:强大的编译时间检查
一般规则是“每个#定义都必须以产生错误的#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来将运行时检查转换成编译时间:static_assert(sizeof(void *)== 4);. 现在这一切都在编译时完成:)
附录A
从上面的规则可以调整,使您的整个代码库更可靠:
- 每个if()语句都以“else”结尾,从而产生警告或错误。
- 每个switch()语句都以“default:”结尾,这会产生警告或错误。
之所以这样做是有效的,是因为它促使你事先考虑每一个案例,而不是依赖(有时是有缺陷的)“其他”部分的逻辑来执行正确的代码。
我使用这种技术(其中包括许多其他技术)来编写一个30,000行的项目,这个项目从最初部署到生产当天(即12个月前)开始就是完美无缺的。
你应该可以使用stdint.h
定义的macros。 特别是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位还是64位窗口,long和int都是32位。 我会认为检查一个指针的大小是否是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,long和void *
这样的大小的下限。 即使编译为64位平台,也不能保证int是64位。 该模型允许例如23位int
s和sizeof(int *) != sizeof(char *)
64位平台有不同的编程模型 。
你最好的select是平台特定的testing。 你的第二好的,便携式的决定必须更具体的什么是64位。
人们已经提出了一些方法来试图确定程序是否被编译为32-bit
或64-bit
。
我想补充一点,你可以使用c ++ 11特性static_assert
来确保这个架构是你认为的(“放松”)。
所以在你定义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
我将32位和64位源放在不同的文件中,然后使用构build系统select适当的源文件。
你的方法不是太遥远,但你只是检查long
和int
是否是相同的大小。 理论上,它们都可以是64位,在这种情况下,你的检查将失败,假设都是32位。 这是一个检查,实际上检查types的大小本身,而不是他们的相对大小:
#if ((UINT_MAX) == 0xffffffffu) #define INT_IS32BIT #else #define INT_IS64BIT #endif #if ((ULONG_MAX) == 0xfffffffful) #define LONG_IS32BIT #else #define LONG_IS64BIT #endif
原则上,您可以对任何types的系统定义macros具有最大值。
请注意,即使在32位系统上,该标准也需要long long
时间才能达到至less64位。
下面的代码适用于大多数当前的环境:
#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
如果您可以在所有环境中使用项目configuration,则可以轻松定义64位和32位符号。 所以你会有这样的项目configuration:
32位debugging
32位版本
64位debugging
64位版本
编辑:这些是通用的configuration,而不是目标configuration。 给你打电话。
如果你做不到,我喜欢Jared的想法。