Опытный
Профиль
Группа: Участник
Сообщений: 312
Регистрация: 8.1.2007
Где: Ленобласть
Репутация: 5 Всего: 23
|
Один из часто встречающихся вопросов начинающих по ассемблеру - как вводить и выводить числа? Подобные темы с завидным упорством и постоянством плодятся на форумах. Поэтому предлагается разобрать его здесь, в FAQ, и на все вопросы по вводу-выводу и смежным темам сначала отправлять сюда. Добавлено @ 23:06Вывод в шестнадцатеричном видеВыведем шестнадцатеричное представление числа в AX. Код | outhex proc near push cx push dx mov cx, 4 ; Очередная цифра получается в младшей тетраде AX после ; сдвига на 4 двоичных разряда, или на один шестнадцатеричный. @oh0: rol ax, 4 mov dl, al and dl, 0Fh ; Далее, смотрим, выводить её цифрой или буквой. Если цифрой, то число надо ; увеличить на 30h, чтобы из 0..9 сделать 30h..39h - коды '0'..'9'. ; Если же буквой, то из 10..15 надо сделать 41h..46h - коды 'A'..'F', ; то есть число увеличить на 37h. cmp dl, 9 jbe short @oh1 add dl, 7 @oh1: add dl, 30h ; Итак, получили код символа в DL. Теперь его надо вывести функцией 2, но ; запись 2 в AH испортит исходное число. push ax mov ah, 02h int 21h pop ax ; И так четыре раза, так как в AX четыре шестнадцатеричные цифры. loop @oh0 pop dx pop cx ret outhex endp
|
Добавлено @ 23:06Ввод шестнадцатеричного числаВведём четырёхзначное шестнадцатеричное число и сохраним его в AX. Код | inhex proc near push cx push dx ; Будем накапливать число в CX. xor cx, cx ; Введём очередную цифру, одновременно показав её на экране. @ih0: mov ah, 01h int 21h ; Теперь надо преобразовать её в число. Надо отобразить ; '0'..'9' (30h..39h) в 0..9, 'A'..'F' (41h..46h) и ; 'a'..'f' (61h..66h) в 10..15, а всё остальное забраковать. ; Ну, что ж, приступим... ; '0'..'9', 'A'..'F', 'a'..'f' => 0..9, 11h..16h, 31h..36h sub al, 30h ; Пользуясь тем, что sub устанавливает флаги так же, как cmp, ; прекращаем ввод, если символ оказался до '0' в таблице ASCII. ; Сюда же, кстати, попадает случай нажатия enter (0Dh). jb short @ih3 ; Теперь смотрим, если это цифра (0..9), то мы её получили. Можно ; добавлять её к числу. cmp al, 09h jbe short @ih2 ; Если же нет, то переводим 11h..16h, 31h..36h в 0..5, 20h..25h. sub al, 11h ; Если исходный символ был между '9' и 'A', прекращаем ввод. jb short @ih3 ; Если он попал в 'A'..'F', перешедший в 0..5, то, чтобы получить ; введённую шестнадцатеричную цифру, осталось прибавить к DL десять. cmp al, 5 jbe short @ih1 ; Если до сих пор не успокоились, то переводим 20h..25h в 0..5. ; Если выскочили за ноль, то введённый символ нужно забраковать. sub al, 20h jb short @ih3 ; Если получили нечто слишком большое, тоже сдаёмся. cmp al, 5 ja short @ih3 ; Иначе исходный символ попал в 'a'..'f', отобразился в 0..5, и теперь, ; если мы прибавим к этому десять, получим введённую шестнадцатеричную цифру. @ih1: add al, 10 ; Итак, в AL очередная цифра. Надо приписать её справа к ; уже имеющемуся в CL числу. Для этого сдвигаем CL на один шестнадцатеричный ; разряд, и заполняем его введённой шестнадцатеричной цифрой. @ih2: shl cx, 4 or cl, al ; Повторяем, пока не надоест вводить нечто шестнадцатеричное. jmp short @ih0 ; Сюда мы попадём, когда введут нецифру. Здесь перейдём на новую строку @ih3: mov ah, 02h mov dl, 0Dh int 21h mov dl, 0Ah int 21h ; и запишем результат в AX. mov ax, cx pop dx pop cx ret inhex endp
|
Добавлено @ 23:07Вывод положительного однобайтового числаВыведем число в AL. Код | outbyte proc near push ax push cx push dx ; Поделим это число на десять. Остаток - правая цифра - ; получится в AL, частное в AH. aam ; Запомним младшую цифру, перейдём к частному. mov cl, al mov al, ah ; Его тоже поделим на десять. В AL получим вторую цифру, ; в AH - частное от деления исходного числа на 100. ; А это старшая цифра, ведь в один байт помещаются ; максимум трёхзначные числа. aam mov ch, al mov dl, ah ; Итак, теперь цифры числа хранятся в DL, CH, CL. ; Приступим к выводу. Заготовим номер функции. mov ah, 02h ; Переведём все цифры в символы. add dl, 30h add cx, 3030h ; Теперь попытаемся избежать вывода значащих нулей. ; Если старшая цифра не ноль, начинаем вывод с неё. cmp dl, 30h jnz short @ob1 ; Если ноль, то проверяем вторую цифру. cmp ch, 30h jnz short @ob2 ; Если она тоже ноль, то выведем только младшую, ; даже если и она ноль. jmp short @ob3 @ob1: int 21h @ob2: mov dl, ch int 21h @ob3: mov dl, cl int 21h pop dx pop cx pop ax ret outbyte endp
|
Добавлено @ 23:07Вывод целого числаВыведем знаковое целое в AX. Код | outint proc near push cx push dx push bx push ax ; Проверяем число на знак. test ax, ax jns short @oi1 ; Если оно отрицательное, выведем минус и оставим его модуль. mov ah, 02h mov dl, '-' int 21h pop ax push ax neg ax ; Количество цифр будем держать в CX. @oi1: xor cx, cx mov bx, 10 @oi2: xor dx, dx div bx ; Делим число на десять. В остатке получается последняя цифра. ; Сразу выводить её нельзя, поэтому сохраним её в стэке. push dx inc cx ; А с частным повторяем то же самое, отделяя от него очередную ; цифру справа, пока не останется ноль, что значит, что дальше ; слева только нули. test ax, ax jnz short @oi2 ; Теперь приступим к выводу. mov ah, 02h @oi3: pop dx ; Извлекаем очередную цифру, переводим её в символ и выводим. add dl, 30h int 21h ; Повторим ровно столько раз, сколько цифр насчитали. loop @oi3 pop ax pop bx pop dx pop cx ret outint endp
|
Добавлено @ 23:08Ввод целого числаВведём знаковое целое и сохраним его в AX. Код | inint proc near push cx push dx push bx push si ; В SI будет признак знака, в BX - число, CX тоже пригодится. xor si, si xor bx, bx xor cx, cx ; Введём первый символ. mov ah, 01h int 21h ; Здесь и только здесь может попасться минус. Если это не так, ; перейдём к обычной обработке символа. cmp al, '-' jne short @ii1 ; Иначе установим признак знака и inc si ; введём следующий символ. @ii0: mov ah, 01h int 21h ; Если символ за '9', то ввод некорректный, прекратим этот беспредел. @ii1: cmp al, 39h ja short @ii2 ; Переводим символ в число. Если при этом получится нечто отрицательное, ; то исходный символ перед '0', значит, ввод можно прерывать. sub al, 30h jb short @ii2 ; Итак, в AL цифра, которую нужно приписать справа к уже имеющемуся ; в BX числу. Поместим цифру из AL в CX. Именно для этого он обнулялся. mov cl, al ; Умножим текущий результат на 10. shl bx, 1 ; BX = 2 * bx mov ax, bx ; AX = 2 * bx shl ax, 2 ; AX = 8 * bx add bx, ax ; BX = 10 * bx add bx, cx ; BX = 10 * bx + al ; И так, пока вводят цифры. jmp short @ii0 ; Когда ввели нецифру, посмотрим, надо ли менять знак, @ii2: test si, si jz short @ii3 neg bx ; перейдём на новую строку @ii3: mov ah, 02h mov dl, 0Dh int 21h mov dl, 0Ah int 21h ; и запишем результат в AX. mov ax, bx pop si pop bx pop dx pop cx ret inint endp
|
Добавлено через 3 минуты и 31 секундуВывод вещественного числаВыведем число в ST(0), заодно вытолкнув его из стэка. Код | ; Требуется директива .286C или выше. outfloat proc near push ax push cx push dx ; Формируем кадр стэка, чтобы хранить в нём десятку ; и ещё какую-нибудь цифру. push bp mov bp, sp push 10 push 0 ; Проверяем число на знак, и если оно отрицательное, ftst fstsw ax sahf jnc @of1 ; то выводим минус mov ah, 02h mov dl, '-' int 21h ; и оставляем модуль числа. fchs ; Пояснение далее пойдёт на примере. ; ST(0) ST(1) ST(2) ST(3) ... ; Отделим целую часть от дробной. ; 73.25 ... что-то не наше @of1: fld1 ; 1 73.25 ... fld st(1) ; 73.25 1 73.25 ... ; Остаток от деления на единицу даст дробную часть. fprem ; 0.25 1 73.25 ... ; Если вычесть её из исходного числа, получится целая часть. fsub st(2), st ; 0.25 1 73 ... fxch st(2) ; 73 1 0.25 ... ; Сначала поработаем с целой частью. Считать количество цифр будем в CX. xor cx, cx ; Поделим целую часть на десять, @of2: fidiv word ptr [bp - 2] ; 7.3 1 0.25 ... fxch st(1) ; 1 7.3 0.25 ... fld st(1) ; 7.3 1 7.3 0.25 ... ; отделим дробную часть - очередную справа цифру целой части исходного числа,- fprem ; 0.3 1 7.3 0.25 ... ; от чатсного оставим только целую часть fsub st(2), st ; 0.3 1 7 0.25 ... ; и сохраним цифру fimul word ptr [bp - 2] ; 3 1 7 0.25 ... fistp word ptr [bp - 4] ; 1 7 0.25 ... inc cx ; в стэке. push word ptr [bp - 4] fxch st(1) ; 7 1 0.25 ... ; Так будем повторять, пока от целой части не останется ноль. ftst fstsw ax sahf jnz short @of2 ; Теперь выведем её. mov ah, 02h @of3: pop dx ; Вытаскиваем очередную цифру, переводим её в символ и выводим. add dl, 30h int 21h ; И так, пока не выведем все цифры. loop @of3 ; 0 1 0.25 ... ; Итак, теперь возьмёмся за дробную часть, для начала проверив её существование. fstp st(0) ; 1 0.25 ... fxch st(1) ; 0.25 1 ... ftst fstsw ax sahf jz short @of5 ; Если она всё-таки ненулевая, выведем точку mov ah, 02h mov dl, '.' int 21h ; и не более шести цифр дробной части. mov cx, 6 ; Помножим дрообную часть на десять, @of4: fimul word ptr [bp - 2] ; 2.5 1 ... fxch st(1) ; 1 2.5 ... fld st(1) ; 2.5 1 2.5 ... ; отделим целую часть - очередную слева цифру дробной части исходного числа,- fprem ; 0.5 1 2.5 ... ; оставим от произведения лишь дробную часть, fsub st(2), st ; 0.5 1 2 ... fxch st(2) ; 2 1 0.5 ... ; сохраним полученную цифру во временной ячейке fistp word ptr [bp - 4] ; 1 0.5 ... ; и сразу выведем. mov ah, 02h mov dl, [bp - 4] add dl, 30h int 21h ; Теперь, если остаток дробной части ненулевой fxch st(1) ; 0.5 1 ... ftst fstsw ax sahf ; и мы вывели менее шести цифр, продолжим. loopnz @of4 ; 0 1 ... ; Итак, число выведено. Осталось убрать мусор из стэка. @of5: fstp st(0) ; 1 ... fstp st(0) ; ... ; Точнее, стэков. leave pop dx pop cx pop ax ret outfloat endp
|
Добавлено через 3 минуты и 55 секундВвод вещественного числаВведём вещественное число и затолкнём его на верщину стэка. Код | ; Требуется директива .286C или выше. infloat proc near push ax push dx push si ; Формируем кадр стэка, чтобы хранить десятку и ещё какую-нибудь цифру. push bp mov bp, sp push 10 push 0 ; В SI признак знака. xor si, si ; Начнём накапливать число. Сначала это ноль. fldz ; Вводим первый символ. Это может быть минус. mov ah, 01h int 21h cmp al, '-' jne short @if1 ; Если это действительно минус, запоминаем это ; и вводим следующую цифру. inc si @if0: mov ah, 01h int 21h ; Если введена точка, то пора переходить ; к формированию дробной части. @if1: cmp al, '.' je short @if2 ; Ну а если нет, то проверим, что ввели цифру ; (в противном случае закончим ввод), cmp al, 39h ja short @if5 sub al, 30h jb short @if5 ; сохраним её во временной ячейке и допишем ; к текущему результату справа, mov [bp - 4], al ; то есть умножим уже имеющееся число на десять fimul word ptr [bp - 2] ; и прибавим только что обретённую цифру. fiadd word ptr [bp - 4] ; И так, пока не надоест. jmp short @if0 ; Если собрались вводить дробную часть, ; то запасёмся единицей. @if2: fld1 ; Вводим нечто. @if3: mov ah, 01h int 21h ; Если это не цифра, сдаёмся. cmp al, 39h ja short @if4 sub al, 30h jb short @if4 ; Иначе сохраняем её во временной ячейке, mov [bp - 4], al ; получаем очередную отрицательную степень десятки, fidiv word ptr [bp - 2] ; дублируем её, fld st(0) ; помножаем на введённую цифру, тем самым получая ; её на нужном месте, fimul word ptr [bp - 4] ; и добавляем к текущему результату. faddp st(2), st ; Опять-таки, пока не надоест. jmp short @if3 ; Если ввод дробной части закончен, ; нам больше не нужна степень десятки. @if4: fstp st(0) ; Итак, на вершине стэка получено введённое число. ; Осталось разве только перейти на новую строку @if5: mov ah, 02h mov dl, 0Dh int 21h mov dl, 0Ah int 21h ; и вспомнить про знак. test si, si jz short @if6 fchs @if6: leave pop si pop dx pop ax ret infloat endp
|
Добавлено через 4 минуты и 19 секундВывод целого числа с обязательным знакомМодифицируем outint так, чтобы в случае положительного числа перед ним выводился знак плюс. Код | outpint proc near push cx push dx push bx push ax test ax, ax ; Изменения коснутся только этой части. ; Если число положительное, переходим на вывод плюса. jns short @op0 mov ah, 02h mov dl, '-' int 21h pop ax push ax neg ax jmp short @op1 @op0: mov ah, 02h mov dl, '+' int 21h pop ax push ax ; Дальше ничего не менялось. @op1: xor cx, cx mov bx, 10 @op2: xor dx, dx div bx push dx inc cx test ax, ax jnz short @op2 mov ah, 02h @op3: pop dx add dl, 30h int 21h loop @op3 pop ax pop bx pop dx pop cx ret outpint endp
|
Это сообщение отредактировал(а) JAPH - 9.6.2007, 23:09
--------------------
Что непонятно - спрашиваем
|