不幸的是,在跨平台、跨编译器环境中,没有单一可靠的方法可以纯粹在编译时执行此操作。
- 如果项目设置有缺陷或损坏(尤其是在 Visual Studio 2008 SP1 上),有时 _WIN32 和 _WIN64都可能未定义。
- 由于项目配置错误,标有“Win32”的项目可能设置为 64 位。
- 根据当前的#define,在 Visual Studio 2008 SP1 上,有时智能感知不会使代码的正确部分变灰。这使得很难在编译时准确查看正在使用的#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”结尾,该“else”会生成警告或错误。
- 每个 switch() 语句都以“default:”结尾,它会生成警告或错误。
之所以如此有效,是因为它迫使您提前考虑每一个案例,而不是依赖“其他”部分中的(有时是有缺陷的)逻辑来执行正确的代码。
我使用这种技术(以及许多其他技术)编写了一个 30,000 行的项目,该项目从它首次部署到生产中的那一天(即 12 个月前)就完美地运行了。