На жаль, у крос-платформі, середовищі компіляції, не існує єдиного надійного способу зробити це чисто під час компіляції.
- Обидва _WIN32 і _WIN64 іноді і невизначені, якщо параметри проекту зіпсовані або пошкоджені (особливо на Visual Studio 2008 SP1).
- Проект із позначкою "Win32" міг бути встановлений на 64-бітне через помилку конфігурації проекту.
- У Visual Studio 2008 SP1 іноді інтелігенція не витісняє правильні частини коду, відповідно до поточного #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 (sizeof (void *) == 4) ;. Тепер це все зроблено під час компіляції :)
Додаток А
До речі, вищезазначені правила можна адаптувати, щоб зробити всю вашу кодову базу надійнішою:
- Кожен оператор if () закінчується на "else", що генерує попередження або помилку.
- Кожен оператор switch () закінчується на "за замовчуванням:", що створює попередження або помилку.
Причина, чому це працює добре, полягає в тому, що вона змушує заздалегідь продумати кожен окремий випадок, а не покладатися на (іноді помилкову) логіку в частині "else" для виконання правильного коду.
Я використав цю техніку (серед багатьох інших), щоб написати проект на 30 000 ліній, який бездоганно працював з дня його першого введення у виробництво (це було 12 місяців тому).