В настоящее время в связи с распространением 64-разрядных процессоров и операционных систем, перед разработчиками программного обеспечения часто встаёт вопрос о программном определении его разрядности.
Это может быть вызвано как декоративными причинами («автоматически» показывать разрядность пользователю, например, «Моя Программа 1.0 64-разрядная версия») так и необходимостью задействовать в различных архитектурах различные алгоритмы с целью максимально эффективного использования их особенностей и при этом сохранить единую кодовую базу.
Простейшие способы
В Delphi для того чтобы определить разрядность приложения достаточно получить размер не типизированного указателя с помощью стандартного приёма.
1 |
sizeof(Pointer); |
В результате будет возвращён размер не типизированного указателя в байтах. Для перевода в биты достаточно умножить полученный результат на 8. В случае 32-разрядного приложения результат будет равен 4 (после умножения 32). В случае же 64-разядного приложения результат будет равен 8 (после умножения 64).
Для C++ существует аналогичный приём.
1 |
sizeof(void*); |
Похожий способ есть и в языке C#. Для того чтобы определить разрядность необходимо узнать размер типа IntPtr. Однако этот тип не имеет предопределённого размера и поэтому прямое использование функции sizeof вызовет синтаксическую ошибку.
Вследствие этого необходимо использовать метод SizeOf класса Marshal из пространства имён System.Runtime.InteropServices (это пространство имён должно быть предварительно задействовано с помощью директивы using). В результате реализация для C# выглядит следующим образом:
1 |
Marshal.SizeOf(typeof(IntPtr)); |
Конечно, это немного более громоздко, чем в случае Delphi или C++.
Всё эти методы предельно просты и доступны даже для начинающих. Однако все они имеют один общий недостаток. При их использовании в программе компилируются одновременно оба варианта кода (и для 32 и для 64-разрядного приложения). В случае небольших проектов или несущественных отличий в алгоритмах между версиями это может оказаться не критично. В противном случае значительный размер программы будет составлять неиспользуемый код. Это приведёт неоправданному увеличению размеров исполняемого файла программы или файла библиотеки в случае DLL. По этой причине все вышеперечисленные методы для реализации специального кода для конкретной архитектуры по большому счёту не пригодны.
Условная компиляция
К счастью, для этого существует альтернатива в виде директив условной компиляции.
В Delphi имеется стандартный символ условной компиляции WIN32, который обозначает 32-разрядную версию операционной системы Windows. С помощью этого символа и директивы компилятора $IFDEF можно указать, какой код будет компилироваться в случае 32-разрядного приложения, а какой в случае 64-разрядного.
Для наглядности приведём простейший пример:
1 2 3 4 5 |
{$IFDEF WIN32} ShowMessage('x86'); {$ELSE} ShowMessage('x64'); {$ENDIF} |
Если приложение 64-разрядное, то будет показано сообщение с текстом «x64».
В C# ситуация значительно сложнее. .Там нет встроенных символов компиляции соответствующих архитектуре по аналогии с вышеупомянутым WIN32 в Delphi. Но их можно легко создать вручную.
Для этого нужно в свойствах проекта, на вкладке «Построение» в поле «Символы условной компиляции» ввести необходимые символы. Например, «x86»
и «x64»,
как показано на скриншотах.
После этого можно воспользоваться вновь созданными символами для того чтобы указать какой именно код для какой архитектуры должен компилироваться.
Для этого следует использовать директиву #if.
1 2 3 4 5 |
#if x86 MessageBox.Show("x86"); #elif x64 MessageBox.Show("x64"); #endif |
В принципе, для решения данной задачи вполне можно обойтись и одним символом. Однако вариант с двумя символами в силу своей большей избирательности обеспечивает лучшее сопровождение кода. Пример приведённый для Delphi проще. Но, в случае его использования на любой платформе отличной от Win32 в файле приложения окажется код предназначенный в том числе для Win64.
Что же касается C++, то ввиду разнообразия компиляторов и различий в их спецификациях конкретное универсальное решение отсутствует. В самом общем случае можно воспользоваться способами, приведёнными для Delphi и C# с поправкой на особенности используемого компилятора.
Ссылки
- Условная компиляция в Delphi 7 – Краткое описание условной компиляции в Delphi. Несмотря на то, что оно было написано для 7й версии, до сих пор является актуальным.
- $IfDef директива компилятора – Описание директивы $IFDEF.
- #if (Справочник по C#) – описание директивы #ifна MSDN.
- Условная компиляция C# – Блог неизвестного человека. Небольшая, но в тоже время очень информативная статья по условной компиляции в C#.
Добавить комментарий