Определение 32 против 64 бит в С++
Я ищу способ достоверно определить, скомпилирован ли код С++ в 32 и 64 бит. Мы придумали разумное решение с использованием макросов, но было любопытно узнать, могут ли люди думать о случаях, когда это может закончиться неудачей или если есть лучший способ сделать это. Обратите внимание, что мы пытаемся сделать это в кросс-платформенной среде с несколькими компиляторами.
#if ((ULONG_MAX) == (UINT_MAX))
# define IS32BIT
#else
# define IS64BIT
#endif
#ifdef IS64BIT
DoMy64BitOperation()
#else
DoMy32BitOperation()
#endif
Спасибо.
Ответы
Ответ 1
К сожалению, нет кросс-платформенного макроса, который определяет 32/64 бит в основных компиляторах. Я нашел наиболее эффективный способ сделать это следующее.
Сначала я выбираю свое собственное представление. Я предпочитаю ОКРУЖЕНИЕ64/ОКРУЖАЮЩУЮ СРЕДУ32. Затем я узнаю, что используют все основные компиляторы для определения, является ли это 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
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;
}
Ответ 3
К сожалению, в кросс-платформенной среде кросс-компилятора нет единого надежного метода для этого во время компиляции.
- Оба _WIN32 и _WIN64 могут иногда и быть undefined, если настройки проекта ошибочны или повреждены (особенно в Visual Studio 2008 SP1).
- Проект с меткой "Win32" может быть установлен на 64-разрядный, из-за ошибки конфигурации проекта.
- В Visual Studio 2008 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);. Теперь все это сделано во время компиляции:)
Приложение A
Кстати, приведенные выше правила могут быть адаптированы, чтобы сделать вашу всю кодовую базу более надежной:
- Каждый оператор if() заканчивается в "else", который генерирует предупреждение или ошибку.
- Каждый оператор switch() заканчивается "по умолчанию:", который генерирует предупреждение или ошибку.
Причина, по которой это хорошо работает, заключается в том, что она заставляет вас думать о каждом отдельном случае заранее и не полагаться на (иногда ошибочную) логику в части "else" для выполнения правильного кода.
Я использовал эту технику (среди многих других) для написания проекта на 30 000 строк, который работал безупречно со дня его первого развертывания в производство (это было 12 месяцев назад).
Ответ 4
Вы должны иметь возможность использовать макросы, определенные в 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 p >
Ответ 5
Это не будет работать в Windows для начала. Longs и ints - 32 бита, независимо от того, компилируете ли вы для 32-битных или 64-битных окон. Я бы подумал, что проверка того, является ли размер указателя 8 байтами, вероятно, более надежным маршрутом.
Ответ 6
Вы можете сделать это:
#if __WORDSIZE == 64
char *size = "64bits";
#else
char *size = "32bits";
#endif
Ответ 7
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
Ответ 8
"Скомпилировано в 64-битном формате" не определено в С++.
С++ устанавливает только нижние пределы для таких размеров, как int, long и void *
. Нет никакой гарантии, что int 64 бит, даже если он скомпилирован для 64-битной платформы. Модель позволяет, например, 23 бит int
и sizeof(int *) != sizeof(char *)
Существуют различные модели программирования для 64-разрядных платформ.
Лучше всего провести тест на платформу. Ваше второе лучшее, переносное решение должно быть более конкретным в 64-битной версии.
Ответ 9
Люди уже предложили методы, которые будут пытаться определить, скомпилирована ли программа в 32-bit
или 64-bit
.
И я хочу добавить, что вы можете использовать функцию С++ 11 static_assert
, чтобы убедиться, что архитектура - это то, что вы думаете ( "расслабиться" ).
Итак, в том месте, где вы определяете макросы:
#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
Ответ 10
Ваш подход не был слишком далек, но вы проверяете только то, что 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
В принципе, вы можете сделать это для любого типа, для которого у вас установлен макрос системы с максимальным значением.
Обратите внимание, что для стандарта требуется long long
быть не менее 64 бит даже в 32-битных системах.
Ответ 11
Ниже код работает отлично для большинства современных сред:
#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__) ) || defined(_M_X64) || defined(__ia64) || defined (_M_IA64) || defined(__aarch64__) || defined(__powerpc64__)
#define IS64BIT 1
#else
#define IS32BIT 1
#endif
Ответ 12
Если вы можете использовать конфигурацию проекта во всех своих средах, это упростит определение 64- и 32-битного символа. Таким образом, у вас будут такие конфигурации проекта, как это:
32-разрядная отладка
32-разрядная версия
64-разрядная отладка
64-разрядная версия
EDIT: это общие конфигурации, а не целевые конфигурации. Назовите их, как хотите.
Если вы не можете этого сделать, мне нравится идея Джареда.
Ответ 13
Я бы разместил 32-битные и 64-разрядные источники в разных файлах, а затем выделил соответствующие исходные файлы, используя систему сборки.
Ответ 14
Я добавляю этот ответ как пример использования и завершаю пример проверки времени выполнения, описанной в другом ответе.
Это тот подход, который я использовал для передачи конечному пользователю, была ли программа скомпилирована как 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]