Ассемблер как ввести число с клавиатуры

Обновлено: 16.05.2024

Не могу найти хороший способ ввода с клавиатуры. Пока остановился на ReadConsoleA + atodw . Но вот только число получается умноженным на 100 + 2428.

Подскажите, почему так получается. И какие ещё есть способы ввода числа с клавиатуры?

3,299 12 12 серебряных знаков 48 48 бронзовых знаков Сейчас нет возможности проверить, почему atodw неправильно может работать. Насколько я понял, это специфичная для masm32 функция, ни в одной стандартной dll ее нет, а под рукой только fasm. Вечером может посмотрю. Как вариант можно вместо нее можно использовать sscanf из msvcrt.dll . Увидеть бы atodw, которая скорее всего в masm32rt.inc. под руками нет . Немного вне темы: а вы нарочно все вычисления производите в памяти, что бы программа работала как можно дольше ? (можно же было просто sub eax, 2428; mov ebx, 100; div ebx регистры для того и сделаны что в них операции в разы быстрее чем с внешней памятью .

третья программа:) ещё не привык, полуслучайно стал преподавать ассемблер в школе, приходится и самому изучать. Спасибо, да, переменные лишние тут. atodw действительно в masm32rt.inc.

Скорее всего ReadConsoleA кладет в буфер перевод каретки принятый в windows, т.е. два байта 0x0D и 0x0A. А функция atodw из masm32 sdk при переводе числа из ascii представления в двоичное не проверяет, что в буфере находятся именно цифры, а выполняет для каждого байта входной строки стандартную операцию для перевода ascii цифры в двоичное представление, т.е. вычитает 0x30 из байта (с игнорированием переполнения).

Вот и получили ваше загадочное число 2428 .

Рекомендую после ввода данных проверять их на то, что они цифры, завершая строку как только встречена первая не цифра (как делают многия языки программирования при попытке конвертации строки в число) и только после этого использовать atodw на строке, очищенной от всего лишнего.

т.е. что то в этом роде (проверять не на чем, код не проверен):

Возможно в masm32 для этого есть готовые функции, но это мне не известно.

Последний раз редактировалось Circiter 27.11.2011, 09:07, всего редактировалось 4 раз(а).

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

main proc far
.
call atoi
push ax
.
main endp

atoi proc ; stdin --> ax
; get data (string) from stdin
mov ah , 0ah
lea dx , maxlen
int 21h

; prepare result
xor dx , dx

; process string
xor ch , ch
mov cl , len
; check for empty string
test cl , cl
jz fail
lea si , buffer
cld

char : lodsb ; get next character
; check current character
cmp al , '0'
jb fail
cmp al , '9'
ja fail
; get digit
sub al , '0'
; multiply dx (current result) by 10
mov bx , dx
shl dx , 2
add dx , bx
shl dx , 1
; update result
xor ah , ah
add dx , ax
loop char

; error handler
fail : .
call exit
ret
atoi endp


Скорее всего, нет. Ведь "число" -- понятие достаточно неопределённое (хотя бы своей разрядностью). Прерывания для ввода отдельных символов, разумеется, есть.

Circiter , о боги! Как же я напишу архиватор…

(Десятичных дробей вроде бы в куче стандартов IEEE есть и стандарт ввода, хотя я тут не знаю. Но уж целых чисел…) Видимо, всё так и есть. Здесь я переспросил после того как узнал, что в группе такая проблема. До этого не гадал даже, что нет ввода целых чисел целиком. Десятичных дробей вроде бы в куче стандартов IEEE есть
Есть, только DOS с IEEE никак не соотносится. DOS сам по себе ориентирован только на 86-й. Хотя да, ещё один промах у меня в том, что соответствующего стандарта IEEE на момент создания и устаканивания DOS могло не быть.

И даже целых строк, именно таким прерыванием (точнее говоря функцией, прерывание-то одно) я пользовался в примере выше.


Вам именно архиватор нужен, вроде tar'а, или компрессор? Попробуйте портировать вот этот древний код марковского сжатия по G.V.Cormack'у (само ядро очень компактно, много места занимает чтение коммандной строки и пр.). Я когда-то пытался, но как всегда не доделал. :)

/* Dynamic Markov Compression (DMC) Version 0.0.0


Copyright 1993, 1987

Gordon V. Cormack
University of Waterloo
cormack@uwaterloo.ca


All rights reserved.

This code and the algorithms herein are the property of Gordon V. Cormack.

Neither the code nor any algorithm herein may be included in any software,
device, or process which is sold, exchanged for profit, or for which a
licence or royalty fee is charged.

Permission is granted to use this code for educational, research, or
commercial purposes, provided this notice is included, and provided this
code is not used as described in the above paragraph.

/* This program implements DMC as described in

"Data Compression using Dynamic Markov Modelling",
by Gordon Cormack and Nigel Horspool
in Computer Journal 30:6 (December 1987)

It uses floating point so it isn't fast. Converting to fixed point
isn't too difficult.

comp() and exp() implement Guazzo's version of arithmetic coding.

pinit(), predict(), and pupdate() are the DMC predictor.

pflush() reinitializes the DMC table and reclaims space

preset() starts the DMC predictor at its start state, but doesn't
reinitialize the tables. This is used for packetized
communications, but not here.

int memsize = 0x1000000 ;

static int threshold = 2 , bigthresh = 2 ;

static node * nodebuf ;
static node * nodemaxp ;
static node * nodesptr ;

Последний раз редактировалось arseniiv 26.11.2011, 23:53, всего редактировалось 1 раз.

$\TeX$

Ну, сжиматель-разжиматель, чтобы были доказательства рабочести. Наверно, попробую что-нибудь простейшее, лишь бы текст сжимался. Псевдокод (красивый в е ) для разных алгоритмов есть в любимой книжке. Только не знаю, стоит ли браться за Лемпел(а|я)—Зива. Выглядит-то тоже просто, но не зн… нет, наверно, лучше не стоит. Простое алфавитное кодирование и баста. Так мы никогда ничего не введём. Вы, наверно, как-то её получали, а как? Искать про функцию DOS 0ah ?

Последний раз редактировалось Circiter 28.11.2011, 16:52, всего редактировалось 3 раз(а).

2 arseniiv
Да, rtfm 0x0a . :)

Последний раз редактировалось arseniiv 28.11.2011, 09:14, всего редактировалось 3 раз(а).

Да-да, я уже сделал рабочее. Только почему-то числа не посылаются куда надо.

-- Пн ноя 28, 2011 12:11:57 --

Circiter , не могли бы вы где-нибудь попытаться скомпилировать вот этот код?:

data segment ; сегмент данных

msg_prompt db 'Enter two integer [5] arrays (delimited by new-lines):' , 0dh , 0ah , '$'
msg_input_err db 0dh , 0ah , 'Number is incorrect or too large. Please enter again.' , 0dh , 0ah , '$'
msg_info db 0dh , 0ah , 'Here is sums, differences, products and quotients:' , 0dh , 0ah , '$'
msg_zero_div db 0dh , 0ah , 'One of the entered numbers to divide is 0. Exitting.' , 0dh , 0ah , '$'
crlf db 0dh , 0ah , '$'

code segment ; сегмент кода
assume CS : code , DS : data

; Ввести число с клавиатуры. Результат в ax (-1, если не удалось ввести число)
enter_number proc
; сохраним значения используемых далее регистров
push cx
push dx
push si
; получаем строку из ввода
mov ah , 0ah ; функция DOS ah ввода с клавиатуры
lea dx , buffer ; загрузим адрес буфера в dx
int 21h ; вызов DOS
; первый байт буфера показывает его длину; он заполнен ещё при инициализации памяти там наверху
; второй символ буфера показывает кол-во введённых символов
lea si , buffer ; загрузим адрес буфера в si для работы со строкой
cld ; обнулим флаг направления, т. е. идём слева направо, увеличивая адрес
inc si ; пропустим первый байт (см. выше)
lodsb ; в al теперь длина строки, si указывает на первый символ введённой строки
xor dx , dx ; обнулим dx, здесь будет лежать результат
xor ch , ch ; обнулим ch, чтобы cx == cl
mov cl , al ; поместим длину строки в cl
; проверяем на пустую строку
test cl , cl ; проверим cl на ненулевость
jz fail ; если 0, строка пустая. Число ввести не удалось
char :
lodsb ; получаем следующий символ в al
cmp al , '0' ; сравним с '0'
jb fail ; al < '0' - нечисловой символ, неудача при вводе
cmp al , '9' ; сравним с '9'
ja fail ; al > '9' - нечисловой символ, неудача при вводе
sub al , '0' ; получим из символа цифру
; обновляем результат
; умножаем его на 10
mov bx , dx
shl dx , 2 ; dx' == 4 dx
add dx , bx ; dx' == 5 dx
shl dx , 1 ; dx' == 10 dx
xor ah , ah ; обнулим ah, чтобы ax == al
add dx , ax ; прибавим к dx результату цифру;
; теперь результат содержит число на одну цифру больше
loop char ; повторим для следующего символа (cx уменьшился на 1)
; здесь cx == 0, вся строка получена и число готово
call newline
mov ax , dx ; результат помещаем в ax
jmp return
; в случае ошибки
fail :
mov ax , - 1 ; ошибка, не удалось ввести число
return :
; восстановим значения регистров
pop si
pop dx
pop cx
ret
enter_number endp

; Вывести строку по адресу из ax
print_str proc
push dx ; сохраним то, что было в dx, т. к. он здесь используются
mov dx , ax ; загрузим адрес строки из ax
mov ah , 09h ; функция DOS 9h вывода на экран
int 21h ; вызов DOS
pop dx ; восстановим значение в dx
ret
print_str endp

; Перевести строку
newline proc
push ax
mov ax , offset crlf
call print_str
pop ax
ret
newline endp

; Вывести число из ax на экран
print_number proc
; Сохраним .
push ax
push bx
push cx
push dx
; Выведем число
test ax , ax ; проверим, не ноль ли число
jz it_is_0 ; выведем тогда '0'
mov cx , 10
digit :
xor dx , dx ; при обнулении dx dx:ax == ax
idiv cx ; найдём очередную цифру в dx и остаток числа в ax
mov bx , ax
mov ah , 06h ; функция DOS 6h вывода символа
xor dh , dh ; чтобы dx == dl
add dl , '0' ; получаем из цифры символ для вывода
int 21h ; вызов DOS
mov ax , bx
test ax , ax ; не ноль ли число
jnz digit ; не ноль: надо печатать остальные цифры
; больше нечего выводить
jmp return_p
it_is_0 :
mov ah , 06h ; функция DOS 6h вывода символа
mov dl , '0' ; символ для вывода
int 21h ; вызов DOS
return_p :
; Восстановим .
pop dx
pop cx
pop bx
pop ax
ret
print_number endp

program :
mov ax , data ; адрес сегмента данных сначала загрузим в ax,
mov ds , ax ; а затем перенесем из ax в ds
; напишем приглашение ввода, введём массивы
mov ax , offset msg_prompt ; поместим адрес строки-подсказки для вывода в ax
call print_str ; выведем эту строку на экран
mov ax , offset arr1 ; поместим в ax адрес начала 1-го массива
call enter_array ; введём 1-й массив
mov ax , offset arr2 ; поместим в ax адрес начала 2-го массива
call enter_array ; введём 2-й массив
; посчитаем
call calculate
; выведем массивы
mov ax , offset msg_info ; поместим адрес строки-описания для вывода в ax
call print_str ; выведем эту строку на экран
mov ax , offset arrS ; в ax адрес массива сумм
call print_array ; напечатаем его
mov ax , offset arrD ; в ax адрес массива разностей
call print_array ; напечатаем его
mov ax , offset arrP ; в ax адрес массива произведений
call print_array ; напечатаем его
mov ax , offset arrQ ; в ax адрес массива частных
call print_array ; напечатаем его
; завершим программу
mov ah , 4ch ; функция 4ch завершения программы
mov al , 0 ; код 0 успешного завершения
int 21h ; вызов DOS
code ends

Вконец никак не пойму, что не так. Почему-то не могу переслать косвенной адресацией в массивы числа. Вроде бы всё правильно, а получается что-то странное: последнее число второго массива вводится, а остальные нули.

-- Пн ноя 28, 2011 12:13:40 --

Заметьте, три переменные maxlen, len и buffer должны быть объявлены именно в такой последовательности -- фактически, их надо понимать как поля C-структуры struct Buf;. Использованная мной dos-функция получает указатель

Эхехее… Я их поменял местами, почитал инструкцию в книге, удивился, как ваш код работал и переписал.

-- Пн ноя 28, 2011 12:14:42 --

Увы, числа вводятся и даже попадают в ax . А вот дальше. И ещё лень переписать функцию вывода числа, чтобы оно было не задом наперёд.

Для ввода символов с клавиатуры используется функция 01h прерывания INT 21h: по адресу 100h введите INT 21h; в регистр AH занесите номер функции 01h; выполните прерывание командой "p". В результате появится мерцающий курсор - это приглашение операционной системы (OS) ввести с клавиатуры любой символ. Например, введите букву "h":

После выполнения прерывания, в регистре AL появилось число 68h (ASCII код буквы "h").

При определении ASCII кода клавиши [F1], в регистр AL заносится число 00h, а рядом с приглашением Debug появляется символ ";". Почему получается такой результат? Следующий раздел поможет разобраться в этом.

ASCII и Scan коды

Каждая клавиша клавиатуры при нажатии вырабатывает код сканирования (Scan code): [F1] формирует Scan код 3Bh, [Q] формирует Scan код 10h и т.д. Коды сканирования позволяют вводить информацию в компьютер и управлять его работой.

В отличие от Scan кода, ASCII код описывает не клавишу, а символ, который изображен на ней. Например, при нажатии клавиши с буквой "Z" вырабатывается Scan код 2Сh. Далее этот код преобразуется в один из ASCII кодов: "Z"=5Ah, "z"=7Ah, "Я"=9Fh, "я"=EFh. Преобразование кода зависит от состояния клавиш [Shift], [Caps Lock] и от текущей кодовой страницы.

Управляющие клавиши: [F1]. [F12], [Ctrl], [Alt] и др., не предназначены для ввода символов, и вырабатывают только Scan код. Для каждой из этих клавиш посылается два кода, один за другим. Первый код всегда 0h, он означает, что следом идет Scan код специальной клавиши.

Чтобы Scan код клавиши [F1] попал в регистр AL, надо выполнить INT 21h дважды:

Проверьте функцию в регистре AH и запустите программу командой "g 104". На приглашение OS надо ответить нажатием клавиши [F1], после чего вы увидите:

Регистр AL содержит Scan код клавиши [F1].

Позже мы используем Scan коды в программе редактирования секторов диска, для операций: управление псевдокурсором, листинг секторов диска и запуск отдельных фрагментов кода.

Считывание одной шестнадцатеричной цифры

Любой символ, запрашиваемый функцией 01h прерывания INT 21h, отображается в регистре AL в виде ASCII кода. Например, клавиатурный ввод символа "9" завершается записью в AL числа 39h. Для преобразования кода в цифру достаточно выполнить вычитание: 39h-30h=9. Этот алгоритм можно использовать для ввода с клавиатуры лобой десятичной цифры. Ввод шестнадцатеричных цифр A . F выполняется аналогично, с той лишь разницей, что код символа уменьшается на 37h.

Следующая программа выполняет запрос символа с клавиатуры, и преобразует этот символ в соответствующее шестнадцатеричное число:

Инструкция JLE (Jump if Less or Equal to) - перейти, если меньше или равно.

Программу следует выполнять в два этапа: "g 10C" и "g". Остановка по адресу 10Сh нужна для просмотра числа, введенного в регистр AL, до того, как прерывание INT 20h вернет все регистры в исходное состояние.

Проведите следующие эксперименты с программой:
- проверьте ввод нечисловых символов ("k", "z", "w" . );
- проверьте ввод строчных числовых символов ("a" . "f").

Данная программа работает корректно только с символами "0". "9" и "A". "F". Позже мы исправим этот недостаток, а пока ввод символов надо контролировать самостоятельно.

Считывание двузначного шестнадцатеричного числа

Алгоритм ввода многозначного числа сводится к последовательному запросу всех его цифр: от старшего разряда к младшему. Далее цифры легко объединяются в исходное число.

Например, надо ввести число B9h. После ввода первой цифры, в регистре AL окажется число Bh. Скопируем это число в регистр DL и сдвинем влево на четыре бита:

Сдвиг выполняется инструкцией SHL (Shift Left - сдвиг влево, работает аналогично SHR). После сдвига, в DL получается число B0h. Далее вводится вторая цифра (в AL попадает 9h). Остается выполнить сложение DL + AL: B0h + 9h = B9h.

Программа ввода двузначного шестнадцатеричного числа:

Запустите программу командой "g 121". Введите двузначное шестнадцатеричное число. Результат ввода должен отобразиться в регистре DL. Завершите программу командой "g".

Испытайте программу с различными двузначными числами. Для ввода шестнадцатеричных чисел используйте только заглавные буквы: "A". "F".

Процедуры

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

Для работы с процедурами используется две инструкции:

В программе вывода на экран двузначного шестнадцатеричного числа, дважды повторялась последовательность из пяти инструкций. Ниже показано, как этот повторяющийся фрагмент оформить в виде процедуры:

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

Программа вывода на экран строки символов от "A" до "J":

Каждый вызов инструкции LOOP сопровождается уменьшением регистра CX на единицу, и проверкой: если CX > 0, то выполняется переход на адрес, указанный в инструкции LOOP. Использование регистра CL (вместо CX) сокращает длину кода на 1 байт, но подвергает программу опасности: если до запуска программы в CH будет записано некоторое число, то LOOP выполнит не 10, а значительно большее количество циклов.

Инструкция INC (Increment - приращение) увеличивает содержимое регистра на единицу. Для уменьшения содержимого регистра на единицу используется инструкция DEC (Decrement).

Запустите программу командой "g". Далее выполните трассировку программы. Не забывайте использовать точку останова (или команду "p") для запуска прерываний.

  1. Используя инструкцию DEC, модифицируйте последнюю программу так,
    чтобы она выводила на экран строку символов: "9876543210".
  2. Используя процедуру печати шестнадцатеричной цифры, напишите программу,
    которая будет выводить на экран содержимое регистровой пары SS:SP.

Инструкция RET передает управление на адрес, следующий за вызовом CALL. Предположим, в программе используется несколько вызовов CALL, передающих управление единственной процедуре. То есть, при каждом вызове, инструкция RET должна возвращать управление на различные адреса. Как RET определяет адрес возврата?

До передачи управления процедуре, CALL копирует адрес возврата в специальную область ОЗУ, называемую - СТЕК. Инструкция RET извлекает адрес возврата из стека, и передает управление инструкции, расположенной по этому адресу.

Стек работает подобно стопке подносов на пружине: когда на верх стопки ставят очередной поднос, то вся стопка немного опускается, а верхний поднос является первым кандидатом на выход. Другими словами, работа стека организована по принципу LIFO ("Last In, First Out" - последним пришел, первым ушел).

При реализации некоторых алгоритмов возникает необходимость написать одну процедуру внутри другой. Такую организацию называют вложенной структурой (вложенным вызовом):

0303
0203
0103
.

вершина стека (SS:SP) ->

В данном примере выполняется три вложенных вызова:
CALL 200, CALL 300, CALL 400. В стек заносятся адреса 103, 203, 303:

вершина стека (SS:SP) ->

По адресу 400 находится инструкция RET, которая извлекает адрес c вершины стека,
и передает управление инструкции по этому адресу. Картина в стеке меняется:

Очередной RET вновь извлекает значение с вершины стека, и передает управление на адрес 203. Последний RET забирает из стека адрес инструкции INT 20, и передает ей управление.

Вершина стека всегда хранится в регистровой паре SS:SP:
SS (Stack Segment - сегмент стека);
SP (Stack Point - смещение стека, или указатель стека).

Чтобы лучше разобраться с работой стека, выполните трассировку приведенного примера. Каждый трассировочный шаг сопровождайте анализом регистров SP и IP.

Работа стека может показаться не очень интересной, однако существует много способов его использования. Полезные свойства стека мы начнем обсуждать уже в следующем разделе.

Использование инструкций PUSH и POP

Инструкция CALL помещает адрес возврата в стек, а RET извлекает и передает его в регистр IP (так управление возвращается из процедуры в программу). Аналогичные действия можно выполнить, используя инструкции PUSH и POP:

Инструкции PUSH и POP позволяют использовать стек в качестве временного хранилища данных. Например, в стеке очень удобно сохранять значения регистров.

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

На помощь приходят инструкции PUSH и POP. В начале каждой процедуры нужно сохранить текущие значения регистров, которые будут использованы в процедуре. В конце процедуры (перед возвращением в программу) восстановить значения регистров из стека, например так:

Сохранение и восстановление регистров AX, CX и DX позволяет использовать их в качестве локальных переменных внутри процедуры.

Работать со стеком надо очень аккуратно. Кроме значений регистров, в стеке хранится адрес возврата из процедуры. Т.е., если хоть один регистр не будет восстановлен, то адрес возврата вовремя не окажется на вершине стека, инструкция RET передаст в IP неправильный адрес, и нормальный ход программы будет нарушен.

Организация пауз в программах

Один из вариантов использования вложенных структур - это организация фиксированных по времени пауз. Наиболее простая процедура задержки выглядит так:

Цикл LOOP адресован сам на себя, и выполняет FFFFh - "пустых оборотов". При частоте процессора 1 GHz, такая процедура будет выполнена за несколько десятков микросекунд.

Для более длительной паузы надо поместить данную процедуру внутрь аналогичного цикла:

0FFFh - определяет задержку в секундах (внешний цикл);
FFFFh - определяет задержку в долях секунды (внутренний цикл).

Выполним приблизительную оценку длительности паузы. Общее количество операций CPU: 0FFF x (FFFF + 3) + 4 = FFF2002. Количество тактов CPU на каждую команду может быть 3, 4 и более. Упростим задачу, взяв 4 такта на операцию: FFF2002 x 4 = 3FFC8008 (тактов CPU). Для CPU с частотой 1 GHz получаем: 3FFC8008h / 1000000000d = 1,073512456 (секунд).

На этом шаге мы приведем текст процедур, позволяющих вводить с клавиатуры и выводить на экран многозначные числа.

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

Дадим краткое описание алгоритмов, использованных при реализации этих процедур.

Процедура ввода принимает символ с клавиатуры и помещает его в стек, увеличивая на единицу значение регистра CX , сохраняющего количество введенных символов. После нажатия пользователем клавиши Enter , из стека извлекается очередная цифра, которая умножается соответственно на 1, 10, 1000 и т.д. Полученное значение прибавляется к результату, находящемуся в регистре BX . Эти операции осуществляются в цикле.

Например, если было введено число 124, то тело цикла будет выполнено 3 раза и при извлечении цифр из стека будет вычислена такая сумма: 4*1+2*10+1*100, что составляет 124.

Процедура позволяет вводить отрицательные числа. В этом случае знак '-' будет последним в стеке, что является признаком завершения цикла.

Процедура вывода числа осуществляет деление значения, находящегося в регистре BX , на 10 и размещение в стеке остатков от деления. После того, как получившееся на очередном шаге частное стало равно нулю, осуществляется извлечение из стека находящихся там символов и вывод их на экран.

При выводе отрицательного числа сначала выводится знак '-', берется соответствующее этому отрицательному положительное число и далее выполняется описанный алгоритм.

Приведем текст модуля, содержащего описанные процедуры.

Понятно, что эти процедуры далеки от совершенства. Они могут послужить основой для написания полнофункциональных процедур.

Отметим, что можно добавить к этим процедурам еще несколько процедур (например, процедуры очистки экрана, установки курсора, вывода строки на экран и т.д.) и оформить их в виде файла, который присоединять к файлу с программой на этапе компоновки при выполнении, например, следующей команды:

Здесь PROG.OBJ - откомпилированный файл с основной программой, SERVIS.OBJ - откомпилированный файл с набором процедур.

Отметим также, что крайне желательно в создаваемых процедурах сохранять используемые в процедуре регистры в начале и восстанавливать их в конце процедуры. Это позволит при разработке основной программы не вспоминать, какие регистры были задействованы в реализации той или иной процедуры.

На следующем шаге мы приведем несколько примеров использования операторов условного перехода .

Читайте также: