我正在寻找一种方法来可靠地确定C ++代码是在32位还是64位编译。我们已经提出了我们认为使用宏的合理解决方案,但很想知道人们是否可以想到这可能会失败的情况,或者是否有更好的方法来做到这一点。请注意,我们正在尝试在跨平台的多编译器环境中执行此操作。
#if ((ULONG_MAX) == (UINT_MAX))
# define IS32BIT
#else
# define IS64BIT
#endif
#ifdef IS64BIT
DoMy64BitOperation()
#else
DoMy32BitOperation()
#endif
感谢。
答案 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)
不幸的是,在跨平台的交叉编译环境中,没有一种可靠的方法可以在编译时完全实现这一点。
因此,唯一可靠的方法是结合 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
在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
一般规则是“每个#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
来自@AI.G
的评论:
4年后(不知道以前是否可能)你可以转换 使用静态断言对运行时检查编译时间: static_assert(sizeof(void *)== 4);。现在,这一切都在编译时完成 :)
从根本上说,上述规则可以进行调整,以使整个代码库更加可靠:
这种方法运作良好的原因在于它会强制您提前考虑每一个案例,而不是依赖“其他”部分中的(有时是有缺陷的)逻辑来执行正确的代码。
我使用这种技术(以及许多其他技术)编写了一个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位int
和sizeof(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)
您的方法并不太远,但您只是检查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位。
答案 10 :(得分:2)
以下代码适用于大多数当前环境:
/usr/local/bin/python
答案 11 :(得分:1)
如果您可以在所有环境中使用项目配置,那么可以轻松定义64位和32位符号。所以你有这样的项目配置:
32位调试
32位版本
64位调试
64位版本
编辑:这些是通用配置,而不是目标配置。无论你想要什么,都打电话给他们。
如果你不能这样做,我喜欢Jared的想法。
答案 12 :(得分:1)
我将32位和64位源放在不同的文件中,然后使用构建系统选择适当的源文件。
答案 13 :(得分:1)
借用Contango的excellent 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]