Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Курсовой (ОС).docx
Скачиваний:
9
Добавлен:
11.06.2015
Размер:
169.11 Кб
Скачать

Как сделать код совместимым с Win64

Вероятно, при преобразовании Win32-кода в x64-код больше всего усилий понадобится для того, чтобы сохранить корректность ваших определений типов. Выше говорилось о системе типов в Win64? Используя Windows-типы, определенные через typedef в заголовочных файлах Windows, а не "родные" для компилятора C++ типы (int, long и др.), мы упростим себе написание чистого Win32-кода, способного работать на платформе x64.

Вероятно, наиболее частая и легко устранимая ошибка, которую можно встретить при переносе кода, вызвана предположением о том, что значение указателя может быть сохранено или перенесено в 32-разрядном типе вроде int, long или даже DWORD. Но вся штука в том, что указатели в Win32 и Win64 имеют разные размеры, а целочисленные типы остались прежней длины.

Здесь помогают типы _PTR, определенные в заголовочных файлах Windows. Такие типы, как DWORD_PTR, INT_PTR и LONG_PTR, позволяют объявлять переменные целочисленного типа, которые всегда имеют достаточный размер для хранения указателя на целевой платформе. Например, переменная, определенная как тип DWORD_PTR, является 32-битной целой при компиляции для Win32 и 64-битной при компиляции для Win64. Немного практики, и использование таких переменных станет вашей второй натурой: объявляя какой-либо тип, вы всегда будете спрашивать себя, нужен здесь DWORD или DWORD_PTR?

Возможны ситуации, где надо точно указывать, сколько именно байтов следует отвести под целый тип. На такие случаи в тех же заголовочных файлах (Basetsd.h и др.), где определяются DWORD_PTR и прочие типы, предлагаются определения целых специфической длины, например INT32, INT64, INT16, UINT32 и DWORD64.

Еще одна проблема, связанная с различиями в размерах типов, относится к форматированию вывода printf и sprintf. Вот я раньше часто грешил конструкциями %X или %08X при форматировании значений указателей и был строго наказан за это при запуске подобного кода в x64-системе. Правильный способ - использование %p, при котором автоматически учитывается размер указателя на целевой платформе. Кроме того, printf и sprintf поддерживают префикс I для типов, размер которых зависит от платформы. Скажем, для вывода значения переменной UINT_PTR можно было бы использовать %Iu. Если же вы точно знаете, что переменная всегда будет 64-битной знаковой, то могли бы указать %I64d.

Вычистив ошибки, вызванные определениями типов, неподходящими для Win64, вы все равно можете остаться с кодом, который работает только на платформе x86. Тогда, вероятно, лучше пойти по простейшему пути и написать две версии функции: одну - для Win32, другую - для x64. И здесь нам очень пригодится набор макросов препроцессора:

M_IX86

_M_AMD64

_WIN64

Правильное использование макросов препроцессора очень важно для написания корректного кросс-платформенного кода. Макросы _M_IX86 и _M_AMD64 применяются только при компиляции под определенную платформу, а _WIN64 - при компиляции для любой 64-разрядной версии Windows, в том числе выпуска для процессоров Itanium.

Пытаясь применить макрос препроцессора, хорошенько подумайте о том, чего вы добиваетесь. Например, действительно ли ваш код специфичен только для процессоров x64? Если да, пишите:

#ifdef _M_AMD64

С другой стороны, если тот же код мог бы работать и на x64, и на Itanium, лучше сделать так:

#ifdef _WIN64

Для себя я принял полезное правило при использовании любого из этих макросов: всегда создавать явные варианты #else (подчеркиваю, явные!), чтобы можно было быстро понять, не пропущено ли что-то. Для примера возьмем плохо написанный код:

#ifdef _M_AMD64

// Здесь находится x64-код

#else

// Здесь находится x86-код

#endif

Что будет, если я теперь скомпилирую его для третьей процессорной архитектуры? Сам того не желая, я скомпилирую x86-код. Гораздо лучше переделать предыдущий код примерно так:

#ifdef _M_AMD64

// Здесь находится x64-код

#elif defined (_M_IX86)

// Здесь находится x86-код

#else

#error !!! Нужно написать код для этой архитектуры

#endif

Одна из частей моего Win32-кода, которую удалось перенести на платформу x64 лишь с большим трудом, - подставляемый (inline) ассемблерный код, не поддерживаемый Visual C++ для x64. Но не бойтесь, любители ассемблера. Существует 64-разрядный MASM (ML64.exe); его вместе с документацией можно получить через MSDN. ML64.exe и другие инструменты для x64 (в том числе CL.EXE и LINK.EXE) доступны из командной строки. Чтобы настроить нужные переменные окружения, достаточно запустить файл VCVARS64.BAT.