不幸的是,在跨平台,跨编译器的环境中,没有一种可靠的方法可以在编译时完全做到这一点。
- 如果项目设置存在缺陷或损坏(尤其是在Visual Studio 2008 SP1上),则_WIN32和_WIN64有时都可能未定义。
- 由于项目配置错误,可能将标记为“ Win32”的项目设置为64位。
- 根据当前的#define,在Visual Studio 2008 SP1上,有时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
简单检查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:”结尾,该警告会生成警告或错误。
之所以如此有效,是因为它迫使您提前考虑每种情况,而不是依靠“其他”部分中的(有时是有缺陷的)逻辑来执行正确的代码。
我使用了这项技术(以及其他许多技术)来编写一个30,000行的项目,该项目从首次部署到生产的那天(即12个月前)就一直完美无缺。