Обучающие курсы:

Обучение профессии "Разработчик C#" + стажировка в Mail.ru
Обучение профессии "Разработчик Python" + трудоустройство
Обучение профессии "Веб-разработчик" + стажировка в Mail.ru


Главная страница
Библиотека (скачать книги)
Скачать софт
Введение в программирование
Стандарты для C++
Уроки по C#
Уроки по Python
HTML
Веб-дизайн
Ассемблер в среде Windows
ActiveX
Javascript
Общее о Линукс
Линукс - подробно
Линукс - новое
Delphi
Паскаль для начинающих
Турбопаскаль
Новости
Партнеры
Наши предложения
Архив новостей





Как видно из этого фрагмента кода, операция сложения двух целочисленных 32-битовых операндов разбита на два этапа. Вначале находится сумма двух младших слов обоих операндов, затем двух старших. К полученной сумме добавляется содержимое флага переноса, а результат помещается в переменную i2. Необходимо также поместить один из операндов в регистр. Первое сложение выполняется командой add, т. к. текущее значение флага переноса для него несущественно. После этого выполняется второе сложение командой adc с учетом флага переноса, установленного предыдущим сложением.

Для вывода полученного результата в окно консоли необходимо вначале преобразовать целое число в строку символов. Такое преобразование можно выполнить при помощи функции WIN API wsprintf. Эта функция очень полезна, т. к. позволяет преобразовать данные арифметического типа в строку. Функция wsprintf будет использоваться нами чрезвычайно широко в примерах последующих глав, поэтому остановимся на ней более подробно.

Функция wsprintf форматирует и запоминает строки символов и арифметических операндов в буфере. Любые аргументы конвертируются и запоминаются в буфере в соответствии с определенными для них спецификациями форматирования. Функция формирует в буфере строку с завершающим нулем и возвращает размер строки в качестве результата. Функция wsprintf объявляется следующим образом:
int wsprintf(LPTSTRlpOut, LPCTSTRlpFmt,...);
где параметры функции:
• LPTSTRlpOut — буфер вывода;
• LPCTSTRlpFmt — строка, задающая формат выводимых переменных.

Третьим параметром функции wsprintf является переменная или список переменных, которые необходимо преобразовать. Иными словами, функция wsprintf может принимать переменное число параметров.
Вызов этой функции в нашей программе и передаваемые параметры показаны в следующем фрагменте кода:
charBuf DB " ", О
len charBuf DD $-charBuf
lpFmt DB "%d",
i2 DD 3657
push DWORD PTR i2
push offset lpFmt
push offset charBuf
call wsprintf
add ESP, 12

Параметры передаются, как обычно, через стек, справа налево. Но есть один нюанс, связанный с так называемым соглашением о передаче параметров. Все функции WIN API используют соглашение stdcaii. Это значит, что по завершению выполнения вызываемой процедуры она сама очищает стек. Однако функция wsprintf использует другое соглашение — cdeci, а это означает, что очищать стек должна вызывающая процедура, т. е. наша программа. Поэтому в исходный текст за оператором вызова процедуры необходимо вставить следующую строку:

add ESP, 12,
Функция wsprintf принимает 3 параметра (это 12 байт), а поскольку стек растет к меньшим адресам, то смысл этого оператора становится понятным. Мы подробно остановимся на вопросах, касающихся передачи параметров из языков высокого уровня в ассемблерные подпрограммы, в главе 3. Можно рекомендовать программистам, пишущим на ассемблере, использовать wsprintf и другие функции преобразования данных, входящие в интерфейс WIN API, в своих приложениях. Можно, конечно, разработать свои собственные процедуры преобразования, например из числового формата в строку и наоборот, однако в этом нет особого смысла. Процедуры преобразования различных типов переменных, написанные разработчиками Microsoft, хорошо оптимизированы, и их применение значительно сэкономит время.

Сохраним текст нашей программы в файле с расширением ASM и откомпилируем ее.
Мы так подробно рассмотрели наши первые приложения для того, чтобы в последующих примерах главы не акцентировать внимание на интерфейсе с операционной системой Windows, а сосредоточиться на анализе интересующего нас кода.
Рассмотрим теперь вычитание двух операндов с повышенной точностью. Для этой операции будем использовать команды sub и sbb.
Команды вычитания sub и sbb являются как бы зеркальным отображением команд сложения. Команды устанавливают флаги состояния в соответствии с результатом операции. Флаг переноса будет означать заем единицы. Например, команда
sub ЕАХ, ЕВХ
выполнит вычитание содержимого регистра ЕВХ ИЗ содержимого регистра ЕАХ, поместив результат в ЕАХ. Флаги состояния будут установлены в соответствии с результатом выполнения команды.

Вычитание с заемом выполняется с помощью команды sbb. Эта команда используется в операциях вычитания с повышенной точностью. При выполнении команды sbb необходимо учитывать значение флага заема. Для получения правильного результата значение заема вычитается из результата, полученного при нормальном вычитании.

Для демонстрации вычитания с повышенной точностью воспользуемся исходным текстом предыдущего примера, сделав некоторые изменения. Заменим группу команд сложения
mov AX, WORD PTR il
add WORD PTR i2, AX
mov AX, WORD PTR il+2
adc WORD PTR i2+2, AX
на группу команд вычитания
mov АХ, WORD PTR il
sub WORD PTR i2, AX
mov AX, WORD PTR il+2
sbb 'WORD PTR i2+2, AX

Для разнообразия поменяем значения операндов il и i2 следующим образом:
11 DD 18709
12 DD -9657

Заголовок окна приложения также изменим:
conTitle DB "Substraction of two integers", 0


 
 
 

Библиотека программиста. 2009.
Администратор: admin@programmer-lib.ru