ассистент каф. КСМ Ковалев М.П.

Криворожский технический университет, Украина

Особенности программирования  в  64-разрядной среде Windows

Данная статья посвящена разработке программного обеспечения для 64-разрядных платформ. В ней рассмотрены преимущества этой платформы, недостатки использования 32-разрядного кода на 64-разрядной платформе, основы 64 –разрядного программирования и способы перевода приложений Win32 на 64-разрядную платформу. Все рассмотренные в статье примеры используют язык C++ и компилируются с помощью Microsoft Visual Studio.NET (версия 7.0).

Необходимость в 64-битовой адресации

Возможность доступа к большим адресным пространствам требуется многим приложениям. Можно было бы привести множество примеров, аналогичных тем, которые перечислены ниже.

·       Приложения для обработки изображений. Система использующая адресное пространство размером 4 Гбайт, в состоянии обеспечить лишь 20-секундное воспроизведение телевизионного изображение  высокой четкости (High-Definition Television, HDTV) в реальных цветах.

·       Автоматизированное проектирование механических(MCAD) и электронных (ECAD) устройств. Для проектирования сложных сборочных узлов требуется наличие более 3 Гбайт памяти, а проектирование микросхем предъявляет к памяти не соизмеримые более высокие требования.

·       Базы данных и хранилища данных. Использование файлов с размерами в несколько сотен Гбайт не является чем-то необычным, и возможность доступа к виртуальным адресным пространствам сопоставимых размеров значительно упрощает обработку таких файлов.  

Перевод 32 в 64

С точки зрения программиста основная трудность при переходе от 32-разрядной модели к 64-разрядной заключается в том, что размер указателя и таких системных типов данных, как size_t и time_t, теперь может составлять 64 байта. Поэтому виртуальное адресное пространство процесса уже не ограничивается 4 Гбайт (фактически доступны приложениям только 3 Гбайт). Таким образом, перенос программы из Win32 в Win64 по существу требует лишь «удаление» указателей, чем связаны самые минимальные последствия для пользовательских данных в модели Windows[1].

В общем виде алгоритм перевода кода Win32 на 64-разрядную платформу выглядит так:

Для создания кросс-платформенных приложений (это предпочтительней первого варианта) необходимо:

К сожалению, пока не существует программ, которые могли бы помочь это сделать. Поэтому все изменения нужно делать самим. Единственным помощником в данном случае является 64-разрядный компилятор: в частности, его режим предупреждений (warnings), касающийся 64-разрядного кода. Для того чтобы включить эти предупреждения, нужно воспользоваться параметром компилятора-Wp64-W3.

Для работы с 64-разрядным кодом понадобятся компилятор, линкер и несколько подключаемых библиотек. Все это есть в последних дистрибутивах SDK и DDK. Прежде всего, необходимо рассмотреть макросы и директивы компилятора, предназначенные для 64-разрядного кода:

Теперь есть возможность создавать приложения, работающие и на 32-, и на 64-разрядной платформах. Здесь есть, однако, немало подводных камней. Следует быть очень внимательным - например, следующий код был вполне пригоден для <старых> приложений, но не для 64-разрядной платформы:

#ifdef _WIN32 // Win32 код

...

#else     // А здесь неясно, какой код

 следует далее: 64- или 16-разрядный...

...

#endif

И этот код не является корректным:

#ifdef _WIN16 // Win16 код

...

#else   // То же самое: 32-

 или 64-разрядный код?

...

#endif

Чтобы исправить этот код, нужно после #else добавить макросы _WIN32 или _WIN64. Просто придется привыкнуть к тому, что теперь код бывает трех (а не двух, как раньше) <видов>, поэтому использование директивы #else в привычных конструкциях приведет к неоднозначности (хотя 16-разрядных приложений становится все меньше и меньше, поддержка этой платформы в современных компиляторах остается).

Теперь рассмотрим новые типы данных. Их можно условно разделить на три группы:

Теперь рассмотрим особенности новых типов данных. Каждый целочисленный тип явного представления имеет размер, соответствующий его определению. Это означает, что переменная типа int32 всегда будет занимать 32 разряда, вне зависимости от платформы, на которой запускается и исполняется код[2]. Обратите внимание, что при следующем макросе

...

#ifdef _WIN32 // Win32 код

...

под 32-разрядным кодом подразумевается использование 32-разрядных типов данных. Именно для переменных этой платформы служит тип int32. То же касается и других целочисленных типов явного представления, имеющих размер 32 разряда.

Второй вид (целочисленные типы, представленные указателями) имеет свою особенность: размер данных каждого такого типа зависит от платформы, на которой исполняется приложение. Именно поэтому многие из этих типов названы интегральными. Они сочетают в себе свойства 32- и 64-разрядных типов. Эти типы можно сравнить с виртуальными функциями и поздним связыванием из объектно-ориентированного программирования, так как в обоих случаях среда исполнения определяет конкретные свойства элементов только во время исполнения приложения, а не компиляции (в этом и заключается позднее связывание). Эти типы данных позволяют создавать приложения, одинаково хорошо работающие на 32- и 64-разрядной платформах.

Далее следуют указатели. При работе с ними надо соблюдать осторожность: необходимо учитывать разрядность данных, которые адресуются указателем, и помнить, что 32-разрядные указатели в 64-разрядном коде всегда расширяются операционной системой до нужного размера.

Заключение

В данной статье  были рассмотреть все значимые аспекты перевода 32-разрядного кода на 64-разрядную платформу. Средства для работы с 64-разрядным кодом (новые типы данных, указатели, компилятор, библиотеки...) включены в новую версию MS Visual C++. С их помощью уже сейчас можно создавать кросс-платформенные приложения и портировать 32-разрядный код.

Литература:

1. Джонсон М. Харт. Системное программирование в среде Windows, 3-е издание.: Пер. с англ. –М.: Издательский дом «Вильямс», 2005. -592с.ил. –Парал.тит.англ.

2.  Открытые Системы. Windows 2000 Magazine, #08/2002. http://www.osp.ru/