К сожалению, в кросс-платформенной среде кросс-компиляции не существует единого надежного способа сделать это исключительно во время компиляции.
- Оба _WIN32 и _WIN64 иногда и неопределенные, если параметры проекта испорчены или повреждены (особенно на Visual Studio 2008 SP1).
- Проект с пометкой «Win32» может быть установлен на 64-разрядную версию из-за ошибки конфигурации проекта.
- В Visual Studio 2008 с пакетом обновления 1 (SP1) иногда intellisense не выделяет правильные части кода в соответствии с текущим #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: static_assert (sizeof (void *) == 4) ;. Теперь все это делается во время компиляции :)
Приложение
Кстати, приведенные выше правила могут быть адаптированы, чтобы сделать всю вашу кодовую базу более надежной:
- Каждый оператор if () заканчивается на «else», которое генерирует предупреждение или ошибку.
- Каждый оператор switch () заканчивается значением «default:», которое генерирует предупреждение или ошибку.
Причина того, что это работает хорошо, заключается в том, что он заставляет вас заранее думать о каждом отдельном случае, а не полагаться на (иногда ошибочную) логику в части «else» для выполнения правильного кода.
Я использовал эту технику (среди многих других), чтобы написать 30-тысячный линейный проект, который работал безупречно со дня, когда он был впервые запущен в производство (это было 12 месяцев назад).