2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




Начать новую тему Ответить на тему На страницу 1, 2  След.
 
 Ввод чисел на ассемблере
Сообщение26.11.2011, 22:31 
Заслуженный участник
Аватара пользователя


27/04/09
25993
Неужели нет функции DOS, которая бы это делала? Неужели надо даже ввод чисел писать «руками»? :shock: Или хотя бы какой-нибудь функции, упрощающей это написание.

 Профиль  
                  
 
 Re: Ввод чисел на ассемблере
Сообщение26.11.2011, 22:58 
Заслуженный участник


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

код: [ скачать ] [ спрятать ]
Используется синтаксис ASM
maxlen db 11
len db 0
buffer db 10 dup(0)
...

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

    mov ax, dx
    ret

    ; error handler
    fail: ...
          call exit
          ret
atoi endp
 

 Профиль  
                  
 
 Re: Ввод чисел на ассемблере
Сообщение26.11.2011, 23:03 
Заслуженный участник


11/05/08
31881
arseniiv в сообщении #508553 писал(а):
Неужели нет функции DOS, которая бы это делала?

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

 Профиль  
                  
 
 Re: Ввод чисел на ассемблере
Сообщение26.11.2011, 23:11 
Заслуженный участник
Аватара пользователя


27/04/09
25993
Ну не скажите. Обычно целые числа имеются в виду конечного числа разрядностей и знаковости. Могли бы 8-16 функций предоставить! :roll:

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

 Профиль  
                  
 
 Re: Ввод чисел на ассемблере
Сообщение26.11.2011, 23:16 
Заслуженный участник


11/05/08
31881

(Оффтоп)

arseniiv в сообщении #508583 писал(а):
Могли бы 8-16 функций предоставить! :roll:

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

 Профиль  
                  
 
 Re: Ввод чисел на ассемблере
Сообщение26.11.2011, 23:24 
Заслуженный участник
Аватара пользователя


27/04/09
25993
(Десятичных дробей вроде бы в куче стандартов IEEE есть и стандарт ввода, хотя я тут не знаю. Но уж целых чисел…) Видимо, всё так и есть. Здесь я переспросил после того как узнал, что в группе такая проблема. До этого не гадал даже, что нет ввода целых чисел целиком.

 Профиль  
                  
 
 Re: Ввод чисел на ассемблере
Сообщение26.11.2011, 23:30 
Заслуженный участник


11/05/08
31881

(Оффтоп)

arseniiv в сообщении #508594 писал(а):
Десятичных дробей вроде бы в куче стандартов IEEE есть

Есть, только DOS с IEEE никак не соотносится. DOS сам по себе ориентирован только на 86-й.

 Профиль  
                  
 
 Re: Ввод чисел на ассемблере
Сообщение26.11.2011, 23:40 
Заслуженный участник
Аватара пользователя


27/04/09
25993

(Оффтоп)

Хотя да, ещё один промах у меня в том, что соответствующего стандарта IEEE на момент создания и устаканивания DOS могло не быть.

 Профиль  
                  
 
 Re: Ввод чисел на ассемблере
Сообщение26.11.2011, 23:42 
Заслуженный участник


26/07/09
1559
Алматы
2ewert
Цитата:
Прерывания для ввода отдельных символов

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

2arseniiv
Цитата:
Как же я напишу архиватор…

Вам именно архиватор нужен, вроде tar'а, или компрессор? Попробуйте портировать вот этот древний код марковского сжатия по G.V.Cormack'у (само ядро очень компактно, много места занимает чтение коммандной строки и пр.). Я когда-то пытался, но как всегда не доделал. :)
код: [ скачать ] [ спрятать ]
Используется синтаксис C
/*   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.

*/


#include <stdio.h>

float predict();
int pinit();
int pupdate();

int memsize = 0x1000000;

main(argc,argv)
   int argc;
   char *argv[];
{
   if (argc == 3 && isdigit(*argv[2])) sscanf(argv[2],"%d",&memsize);
   if (argc >= 2 && *argv[1] == 'c') comp();
   else if (argc >= 2 && *argv[1] == 'e') exp();
   else {
      fprintf(stderr,"usage:  dmc [ce] memsize <infile >outfile\n");
      exit(1);
   }
   return 0;
}

comp(){
   int max = 0x1000000,
       min = 0,
       mid,
       c,i,
       inbytes = 0,
       outbytes =3,
       pout = 3,
       bit;
   
   pinit(memsize);
   
   for(;;){
      c = getchar();
      if (c == EOF) {
         min = max-1;
         fprintf(stderr,"compress done: bytes in %d, bytes out %d, ratio %f\n",
                         inbytes,outbytes,(float)outbytes/inbytes);
         break;
      }
      for (i=0;i<8;i++){
         bit = (c << i) & 0x80;
         mid = min + (max-min-1) * predict();
         pupdate(bit != 0);
         if (mid == min) mid++;
         if (mid == (max-1)) mid--;
   
         if (bit) {
            min = mid;
         } else {
            max = mid;
         }
         while ((max-min) < 256) {
            if(bit)max--;
            putchar(min >> 16);
            outbytes++;
            min = (min << 8) & 0xffff00;
            max = ((max << 8) & 0xffff00 ) ;
            if (min >= max) max = 0x1000000;
         }
      }
      if(!(++inbytes & 0xff)){
         if(!(inbytes & 0xffff)){
               fprintf(stderr,
                       "compressing... bytes in %d, bytes out %d, ratio %f\r",
                       inbytes,outbytes,(float)outbytes/inbytes);
         }
         if (outbytes - pout > 256) { /* compression failing */
            pflush();
         }
         pout = outbytes;
      }
   }
   putchar(min>>16);
   putchar((min>>8) & 0xff);
   putchar(min & 0x00ff);
}


exp(){
   int max = 0x1000000,
       min = 0,
       mid,
       val,
       i,
       inbytes=3,
       pin=3,
       outbytes=0,
       bit,
       c;
   
   pinit(memsize);
   
   val = getchar()<<16;
   val += getchar()<<8;
   val += getchar();
   while(1) {
      c = 0;
      if (val == (max-1)) {
         fprintf(stderr,"expand: input %d output %d\n",inbytes,outbytes);
         break;
      }
      for (i=0;i<8;i++){
         mid = min + (max-min-1)*predict();
         if (mid == min) mid++;
         if (mid == (max-1)) mid--;
         if (val >= mid) {
            bit = 1;
            min = mid;
         } else {
            bit = 0;
            max = mid;
         }
         pupdate(bit != 0);
         c = c + c + bit;
         while ((max-min) < 256) {
            if(bit)max--;
            inbytes++;
            val = (val << 8) & 0xffff00 | (getchar()& 0xff);
            min = (min << 8) & 0xffff00;
            max = ((max << 8) & 0xffff00 ) ;
            if (min >= max) max = 0x1000000;
         }
      }
      putchar(c);
      if(!(++outbytes & 0xff)){
         if (inbytes - pin > 256) { /* compression was failing */
            pflush();
         }
         pin = inbytes;
      }
   }
}

typedef struct nnn {
           float count[2];
           struct nnn    *next[2];
} node;

static int threshold = 2, bigthresh = 2;

static node *p, *new, nodes[256][256];

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

#include <malloc.h>

pinit(memsize)
   int memsize;
{
   fprintf(stderr,"using %d bytes of predictor memory\n",memsize);
   nodebuf = (node *) malloc (memsize);
   if (nodebuf == (node *) NULL) {
      fprintf(stderr,"memory alloc failed; try smaller predictor memory\n");
      exit(1);
   }
   nodemaxp = nodebuf + (memsize/sizeof(node)) - 20;
   pflush();
}

pflush(){
   int i,j;
   for (j=0;j<256;j++){
      for (i=0;i<127;i++) {
         nodes[j][i].count[0] = 0.2;
         nodes[j][i].count[1] = 0.2;
         nodes[j][i].next[0] = &nodes[j][2*i + 1];
         nodes[j][i].next[1] = &nodes[j][2*i + 2];
      }
      for (i=127;i<255;i++) {
         nodes[j][i].count[0] = 0.2;
         nodes[j][i].count[1] = 0.2;
         nodes[j][i].next[0] = &nodes[i+1][0];
         nodes[j][i].next[1] = &nodes[i-127][0];
      }
   }
   nodesptr = nodebuf;
   preset();
}

preset(){
   p = &nodes[0][0];
}

float predict(){
   return   p->count[0] / (p->count[0] + p->count[1]);
}

pupdate(b)
   int b;
{
   float r;
   if (p->count[b] >= threshold &&
      p->next[b]->count[0]+p->next[b]->count[1]
       >= bigthresh + p->count[b]){
      new = nodesptr++;
      p->next[b]->count[0] -= new->count[0] =
         p->next[b]->count[0] *
         (r = p->count[b]/(p->next[b]->count[1]+p->next[b]->count[0]));
      p->next[b]->count[1] -= new->count[1] =
         p->next[b]->count[1] * r;
      new->next[0] = p->next[b]->next[0];
      new->next[1] = p->next[b]->next[1];
      p->next[b] = new;
   }
   p->count[b]++;
   p = p->next[b];
   if (nodesptr > nodemaxp){
      fprintf(stderr,"flushing ...\n");
      pflush();
   }
}

 

 Профиль  
                  
 
 Re: Ввод чисел на ассемблере
Сообщение26.11.2011, 23:52 
Заслуженный участник
Аватара пользователя


27/04/09
25993
Ну, сжиматель-разжиматель, чтобы были доказательства рабочести. Наверно, попробую что-нибудь простейшее, лишь бы текст сжимался. Псевдокод (красивый в $\TeX$е :-)) для разных алгоритмов есть в любимой книжке. Только не знаю, стоит ли браться за Лемпел(а|я)—Зива. Выглядит-то тоже просто, но не зн… нет, наверно, лучше не стоит. Простое алфавитное кодирование и баста.

 Профиль  
                  
 
 Re: Ввод чисел на ассемблере
Сообщение28.11.2011, 02:44 
Заслуженный участник
Аватара пользователя


27/04/09
25993
Зачем вы ввели len? :shock: Только щас дошло:
Используется синтаксис ASM
len db 0
; ...
mov cl, len
test cl, cl
jz fail
 
Так мы никогда ничего не введём. Вы, наверно, как-то её получали, а как? Искать про функцию DOS 0ah?

 Профиль  
                  
 
 Re: Ввод чисел на ассемблере
Сообщение28.11.2011, 03:17 
Заслуженный участник


26/07/09
1559
Алматы
2arseniiv
Да, rtfm 0x0a. :)

Она принимает указатель на специально организованный буфер. Заметьте, три переменные maxlen, len и buffer должны быть объявлены именно в такой последовательности -- фактически, их надо понимать как поля C-структуры struct Buf{char maxlen, len, buffer[10];};. Использованная мной dos-функция получает указатель (maxlen) на структуру, затем читает строку (ограничение на длину хранится в maxlen) с консоли и записывает её в эту структуру -- длину в len, данные в buffer. Вот и всё. Вы же просили что-то, что могло бы упростить ввод. А дальше уже идет примитивный парсер, проверяющий, падают ли символы в диапазон от '0' до '9', и обновляющий результат по формуле $r\gets10r+d$.

 Профиль  
                  
 
 Re: Ввод чисел на ассемблере
Сообщение28.11.2011, 08:37 
Заслуженный участник
Аватара пользователя


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

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

Circiter, не могли бы вы где-нибудь попытаться скомпилировать вот этот код?:
код: [ скачать ] [ спрятать ]
Используется синтаксис ASM
data segment    ; сегмент данных

buffer          db 8, 7 dup (0) ; буфер для строки при вводе-выводе числа

arr1                    dw 5 dup (0)    ; первый массив
arr2                    dw 5 dup (0)    ; второй массив
arrS                    dw 5 dup (0)    ; массив сумм
arrD                    dw 5 dup (0)    ; массив пвзностей
arrP                    dw 5 dup (0)    ; массив произведений
arrQ                    dw 5 dup (0)    ; массив частных
count                   db 5                                    ; длина массивов

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, '$'

data ends

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
enter_array proc
        ; сохраним значения из используемых регистров
        push bx
        push cx
        push di
        mov bx, ax                      ; загрузим адрес массива из ax в bx
        xor ch, ch
        mov cl, count           ; будем повторять цикл count раз
        xor di, di                      ; получем индекс первого элемента 0
        elem:
                jmp input_try
                reinput:
                mov ax, offset msg_input_err
                call print_str                  ; выведем сообщение об ошибке ввода
                jmp input_try                           ; повторим ввод
                input_try:
                        call enter_number       ; введём число
                        cmp ax, -1                                      ; сравним результат с -1
                        je reinput                                      ; если ax == -1, была ошибка при вводе числа. Повторим его
                        ; число введено
                mov [bx]+di, ax         ; поместим число в элемент массива с индексом di
                add di, 2                                      
                loop elem                                       ; если cx == 0, то также di == -1, все элементы массива введены
                                                                                        ; иначе, обработаем следующий элемент
        ; восстановим значения в регистрах
        pop di
        pop cx
        pop bx
        ret
enter_array 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

; Вычислить суммы, разности и остальные чисел массивов
calculate proc
  ; Сохраним значения из регистров
        push ax
        push bx
        push cx
        push dx
        push di
        ; Собственно, цикл с расчётами
        xor ch, ch
        mov cl, count           ; будем повторять цикл count раз
        xor di, di                      ; получем индекс первого элемента 0
        elem_c:
                mov ax, arr1+[di]       ; из первого массива число в ax
                mov dx, arr2+[di]       ; из второго массива число в dx
                ; сразу проверим второе число на ноль, чтобы зря не +-*, если нельзя делить
                test dx, dx                             ; проверим на ноль
                jz fail_c                                       ; 0 - ошибка
                ; можно спокойно считать
                mov bx, ax                              ; чтобы не затереть ax: число нужно и для других операций
                add bx, dx                              ; складываем
                mov arrS+[di], bx       ; сумму в массив сумм
                mov bx, ax                             
                sub bx, dx                              ; вычитаем
                mov arrD+[di], bx       ; разность в свой массив
                mov bx, ax                             
                mul dl                                          ; умножаем
                mov arrP+[di], ax       ; произведение в свой массив
                mov ax, bx                              ; возвращаем обратно изменённый умножением результат
                div dl                                          ; делим; остаток в ah
                xor ah, ah                              ; обнулим остаток, чтобы ax == al
                mov arrQ+[di], ax       ; частное в массив частных
                add di, 2                                      
                loop elem_C                             ; если cx == 0, то также di == -1, все элементы перебраны
                                                                                        ; иначе, обработаем следующий элемент
        jmp return_c
        ; ошибка
        fail_c:
                mov ax, offset msg_zero_div
                call print_str                  ; выведем сообщение об ошибке  
        return_c:
        ; Восстановим регистры
        pop di
        pop dx
        pop cx
        pop bx
        pop ax
        ret
calculate 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

; Вывести массив на экран. Адрес массива берётся из ax
print_array proc
        ; Сохраним ...
        push ax
        push bx
        push cx
        push dx
        push di
        ; Вывод элементов массивов
        mov bx, ax
        xor ch, ch
        mov cl, count           ; будем повторять цикл count раз
        xor di, di                      ; получем индекс первого элемента 0
        elem_p:
                mov ax, [bx]+di         ; текущий элемент в ax
          call print_number     ; и напечатаем это число
                mov ah, 06h                             ; функция DOS 6h вывода символа
                mov dl, ' '       ; пробел между элементами
          int 21h                                               ; вызов DOS
                add di, 2                                      
                loop elem_p                             ; если cx == 0, то также di == -1, все элементы перебраны
        call newline            ; перейдём на новую строку
        ; Восстановим ...
        pop di
        pop dx
        pop cx
        pop bx
        pop ax
        ret
print_array 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

s segment stack         ; сегмент стека
        db 256 dup (0)  ; резервируем под него 256 байт
s ends

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

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

Circiter в сообщении #509066 писал(а):
Заметьте, три переменные maxlen, len и buffer должны быть объявлены именно в такой последовательности -- фактически, их надо понимать как поля C-структуры struct Buf{char maxlen, len; char buffer[10];};. Использованная мной dos-функция получает указатель
Эхехее… Я их поменял местами, почитал инструкцию в книге, удивился, как ваш код работал и переписал. :mrgreen:

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

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

 Профиль  
                  
 
 Re: Ввод чисел на ассемблере
Сообщение28.11.2011, 10:25 
Заслуженный участник


28/04/09
1884
Покопался в своих старинных исходниках и нашел вот это:
код: [ скачать ] [ спрятать ]
Используется синтаксис ASM
;Процедуры ввода-вывода знаковых и беззнаковых чисел (размером 1 и 2 байта)

    ;Процедура: in_value
    ;Описание:
    ;Ввод двухбайтового десятичного числа с контролем ввода и BackSpace
    ;Параметры: нет
    ;Возвращает:
    ;ax - вводимое число
    ;Примечание:
    ;Дополнительно используются регистры cx, dx и si
    in_value proc near ;ввод числа в ax
        mov si, 0 ;установка счетчика в 0
        in_value_m1: ;цикл
            mov ah, 08h ;функция ввода символа без эха с ожиданием
            int 21h
            cmp al, 08h ;сравнение с BackSpace
            jnz in_value_l2 ;введен именно он
                cmp si, 0 ;сравниваем число введенных символов с 0
                jz in_value_l2 ;введен хотя бы один символ
                    mov dl, 08h ;выводимый символ - BackSpace
                    mov ah, 02h ;функция вывода одного символа
                    int 21h
                    mov dl, ' ' ;выводимый символ - Пробел
                    mov ah, 02h ;функция вывода одного символа
                    int 21h
                    mov dl, 08h ;выводимый символ - BackSpace
                    mov ah, 02h ;функция вывода одного символа
                    int 21h
                    dec si ;уменьшаем число цифр на 1
                    pop ax ;забираем из стека введенную цифру
                    jmp in_value_m1 ;переходим ко вводу следующей цифры
            in_value_l2: ;отсутствие BackSpace или невозможность его выполнения
            cmp al, 0Dh ;сравнение с Enter
            jnz in_value_l3 ;введен именно он
                cmp si, 0 ;сравниваем число введенных символов с 0
                jz in_value_l3 ;введен хотя бы один символ
                    mov dl, 0Dh ;выводимый символ - Enter
                    mov ah, 02h ;функция вывода одного символа
                    int 21h
                    mov dl, 0Ah ;выводимый символ - VerticalTab
                    mov ah, 02h ;функция вывода одного символа
                    int 21h
                    jmp in_value_l4 ;переходим к формированию введенного числа
            in_value_l3: ;отсутствие Enter или невозможность его выполнения
            cmp si, 3 ;сравниваем число введенных символов с 3
                jz in_value_m1 ;ждем ввода очередного символа
            sub al, '0' ;номер цифры
            cmp al, 9 ;сравниваем с 9
                jz in_value_l1 ;если равно 9
                    jc in_value_l1 ;если меньше 9
                        jmp in_value_m1 ;переходим к новой цифре
            in_value_l1: ;al находится в интервале 0..9
            mov ah, 0 ;обнуляем верхушку ax
            push ax ;заносим ax в стек
            add al, '0' ;находим код цифры (al)
            mov dl, al ;выводимый символ - введенная цифра
            mov ah, 02h ;функция вывода одного символа
            int 21h
            inc si ;увеличиваем число введенных цифр на 1
        jmp in_value_m1 ;в начало цикла
        in_value_l4: ;формируем число из цифр в стеке
        mov bx, 1 ;начальное значение порядка цифр
        mov cx, 0 ;начальное значение формируемого числа
        in_value_m2: ;цикл
            pop ax ;вытаскиваем из стека очередную цифру (ax)
            mul bx ;домножаем ее на порядок
            add cx, ax ;и прибавляем к формируемому числу
            mov ax, bx ;пересылаем bx в ax
            mov dl, 10 ;основание системы для вывода
            mul dl ;наращиваем ax (порядок)
            mov bx, ax ;пересылаем порядок обратно (ax в bx)
            dec si ;уменьшаем счетчик
            cmp si, 0 ;сравниваем номер текущей цифры с нулем
        jnz in_value_m2 ;в начало цикла
        mov ax, cx ;пересылаем сформированное число в ax
        ret ;выход из процедуры
    in_value endp

    ;Процедура: out_value
    ;Описание:
    ;Вывод числа в системе счисления с основанием, не большим 10
    ;Параметры:
    ;ax - выводимое число
    ;bl - основание системы счисления для вывода (не более 10)
    ;Возвращает: нет
    ;Примечание:
    ;Дополнительно используются регистры cx и dx
    out_value proc near ;выводит на экран число в ax
        cmp bl, 10 ;сравниваем с 10
            jz out_value_l1 ;если равно 10
                jc out_value_l1 ;если меньше 10
                    mov bl, 10 ;записываем в bl 10
        out_value_l1: ;теперь bl меньше либо равно 10
        cmp bl, 0 ;сравниваем с 0
            jnz out_value_l2 ;не равно 0
                mov bl, 10 ;равно 0
        out_value_l2: ;теперь bl больше 0 и не меньше 10
        mov bh, 0 ;установка верхушки bx в 0
        mov cx, 0 ;установка счетчика в 0
        out_value_m1: ;цикл
            mov dx, 0 ;обнуляем верхушку двойного слова dx:ax
            div bx ;ax / bx -> ax, ax % bx -> dx
            push dx ;заталкиваем в стек очередную цифру (dx)
            inc cx ;наращиваем счетчик
            cmp ax, 0 ;сравниваем частное от деления с нулем
        jnz out_value_m1 ;в начало цикла
        out_value_m2: ;цикл
            pop dx ;вытаскиваем из стека очередную цифру (dx)
            add dl, '0' ;корректируем код цифры в ASCII
            mov ah, 02h ;подготовка к выводу символа
            int 21h
            dec cx ;уменьшаем счетчик
            cmp cx, 0 ;сравниваем номер текущей цифры с нулем
        jnz out_value_m2 ;в начало цикла
        ret ;выход из процедуры
    out_value endp

    ;Процедура: out_signed_byte
    ;Описание:
    ;Вывод числа в системе счисления с основанием, не большим 10 (со знаком)
    ;Параметры:
    ;al - выводимое число
    ;bl - основание системы счисления для вывода (не более 10)
    ;Возвращает: нет
    ;Примечание:
    ;Дополнительно используются регистры cx и dx
    out_signed_byte proc near ;выводит на экран число в al
        mov cl, al ;сохраняем al в cl
        and al, 80h ;домножаем на 80h (1 в старшем разряде)
        cmp al, 0 ;сравниваем результат с нулем
        jz out_signed_byte_l1 ;al - положительное число
            mov dl, '-' ;выводимый символ - знак "минус"
            mov ah, 02h ;функция вывода одного символа
            int 21h
            neg cl ;инвертируем знак
        out_signed_byte_l1: ;знак, если он есть, уже выведен
        mov ah, 0 ;обнуляем верхушку ah
        mov al, cl ;вынимаем значение из cl
        call out_value ;выводим абсолютное значение al
        ret ;выход из процедуры
    out_signed_byte endp

    ;Процедура: out_signed_word
    ;Описание:
    ;Вывод числа в системе счисления с основанием, не большим 10 (со знаком)
    ;Параметры:
    ;ax - выводимое число
    ;bl - основание системы счисления для вывода (не более 10)
    ;Возвращает: нет
    ;Примечание:
    ;Дополнительно используются регистры cx и dx
    out_signed_word proc near ;выводит на экран число в ax
        mov cx, ax ;сохраняем ax в cx
        and ax, 8000h ;домножаем на 8000h (1 в старшем разряде)
        cmp ax, 0 ;сравниваем результат с нулем
        jz out_signed_word_l1 ;ax - положительное число
            mov dl, '-' ;выводимый символ - знак "минус"
            mov ah, 02h ;функция вывода одного символа
            int 21h
            neg cx ;инвертируем знак
        out_signed_word_l1: ;знак, если он есть, уже выведен
        mov ax, cx ;вынимаем значение из cx
        call out_value ;выводим абсолютное значение ax
        ret ;выход из процедуры
    out_signed_word endp
Только, по правде говоря, совершенно не помню чем это тогда компилировалось (возможны проблемы совместимости с современными компиляторами). Помню только, что программа работала под DOS.

Тут при вводе контролируется нажатие Enter (если ничего не введено, не сработает) и BackSpace (сотрет один символ, если что-то уже было введено), а при выводе можно выводить в т.ч. отрицательные числа в системе счисления с основанием, не большим 10 (буквы я тогда задействовать поленился, по-видимому).

(Оффтоп)

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

 Профиль  
                  
 
 Re: Ввод чисел на ассемблере
Сообщение28.11.2011, 17:30 
Заслуженный участник
Аватара пользователя


27/04/09
25993

(Оффтоп)

Для лабораторной работы. :-)

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 27 ]  На страницу 1, 2  След.

Модераторы: Toucan, maxal, PAV, Karan, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group