PDA

Просмотр полной версии : Отрицательные числа в массиве



Xariec
04.04.2009, 16:20
Доброго всем времени суток. В институте дали задание, и я понял что в низкоуровневом программировании у меня обстоят дела просто ужасно, за сим обращаюсь за помощью и пояснением.
Условие:

Дан массив из десяти целых знаковых чисел (слов, байт, двойных слов). Заменить все отрицательные числа нулями.
Вот до чего пока что дошел.


.386
.MODEL SMALL
.STACK 4069
.data
array SBYTE 10h,-10h,20h,-20h,30h,-30h,40h,-40h,50h,-50h
zero = 0

.code
main PROC
mov cx,10 ;устанавливаем счетчик
@loop:
mov esi,OFFSET array
mov al,[esi]
inc esi

no:

main ENDP

Понимаю, что для каждого элемента надо проверить значение старшего бита или флаг SF. Как это сделать? Реализовать условие в других языках элементарно, а вот в ассемблере не могу :( Помогите пожалуйста.

somewhere
04.04.2009, 20:21
здесь это можно сделать любой операцией, отличной от mov, не изменяющей операнд. Например:
test al, al
test byte ptr [esi]
or al, al
and byte ptr [esi], 255
ну и т.д., в результате флаги установятся в зависимости от содержимого AL или [ESI], потом делаем условный переход js.
Можно сделать и без перехода (проверки), например вот таким хитрым способом.


movsx ax, byte ptr [esi]
not ah
and al, ah
mov [esi], al

... и все это в цикле. Вообщем разбирайтесь.

Xariec
04.04.2009, 21:55
somewhere, благодарю за скорый ответ!
Вот что у меня получилось:

TITLE ;Задание: Заменить все отрицательные числа массива нулями (One.asm)

.386
.MODEL COMPACT
.STACK 100h
.data
intarray SBYTE 10h,-10h,20h,-20h,30h,-30h,40h,-40h,50h,-50h
zero=0
.code
main PROC
mov cx,10 ;устанавливаем счетчик цикла
mov edi,OFFSET intarray ;загружаем адрес массива intarray
mov eax,zero ;обнуляем аккумулятор
@loop:
mov eax,[edi] ;заносим значение текущего элемента массива в аккумулятор
test eax,eax
js SF1 ;проверяем состояниек флага знака
loop @loop ;возвращаемся на метку @loop
SF1:
mov [edi],zero ;заменяем отрицательное число нулем

main END
INT 21h
END main
но компилятор сообщает о трёх ошибках:
http://img80.imageshack.us/img80/3999/tasm.jpg

airyashov
06.04.2009, 09:32
TITLE ;Задание: Заменить все отрицательные числа массива нулями (One.asm)

.386
.MODEL COMPACT
.STACK 100h
.data
intarray db 10h,-10h,20h,-20h,30h,-30h,40h,-40h,50h,-50h
zero=0
.code
main PROC
mov cx,10 ;устанавливаем счетчик цикла
mov edi,OFFSET intarray ;загружаем адрес массива intarray
mov eax,zero ;обнуляем аккумулятор
@loop:
mov al,[edi] ;заносим значение текущего элемента массива в аккумулятор
test al,al
jns next ;проверяем состояниек флага знака
mov byte ptr[edi],zero ;заменяем отрицательное число нулем
next:
add edi,1
loop @loop ;возвращаемся на метку @loop


main ENDp
INT 21h
END main

BBB
06.04.2009, 10:34
А почему бы просто не сравнить с нулем?
Насколько я помню ASM, есть команды проверки флагов для беззнакового сравнения (jb [Jump if Below], ja [Jump if Above]) и для знакового сравнения (jl [Jump if Less], jg [Jump if Greater])

Т.е. фрагмент может выглядеть так:

Cmp eax, 0
jl SF1 ; переход, если eax меньше 0
loop @loop ; возвращаемся на метку @loop
SF1:
mov byte ptr[edi],zero ; заменяем отрицательное число нулем


А если есть свободный регистр, то перед циклом его можно обнулить, и проводить сравнение не с константой 0, а с этим регистром. Кажется, это будет, типа, оптимальнее в смысле быстродействия :)


Xor edx, edx ; обнуляем регистр edx
Cmp eax, edx
jl SF1 ; переход, если eax меньше 0
loop @loop ;возвращаемся на метку @loop
SF1:
mov byte ptr[edi],zero ;заменяем отрицательное число нулем

somewhere
06.04.2009, 10:50
А если есть свободный регистр, то перед циклом его можно обнулить, и проводить сравнение не с константой 0, а с этим регистром
Начиная с 386 нет никакой разницы. Да и способов проверки и выставления флагов великое множество. В любом случае приведеный код работать не будет и в любом случае установит первый элемент в 0. Виной тому:
1) EDI не меняется в цикле
2) Элементы массива объявлены как байты, а в коде mov eax, [edi]
3) При нахождении отрицательного числа цикл прекращается

Xariec
06.04.2009, 20:38
Благодарю за правку. Только поясните мне следующее:


mov byte ptr[edi],zero

Зачем в комманде пересылки мы ставим "byte ptr[edi]"?

somewhere
06.04.2009, 22:22
Зачем в комманде пересылки мы ставим "byte ptr[edi]"?
Компилятор, не обладая ИИ, не может угадать какой именно ноль записывать в память. Это может быть 8,16,32 битовый ноль. По сути нет разницы между mov [edi], byte ptr 0 или mov byte ptr [edi], 0. В обоих случаях мы дали понять, что нужно записать именно 8 бит по указанному адресу.

Xariec
07.04.2009, 20:38
Прошу прощения, но мне опять требуется ваша помощь:
Не могу найти материал и разобраться в управлении памятью в MS-DOS:
Условие таково:
Установить стратегию "последний подходящий", выделить блок памяти размером 16П, увеличить его размер до 64П

airyashov
08.04.2009, 08:45
насчет памяти это здесь
http://www.codenet.ru/progr/dos/int_0026.php
Функция DOS 48H: распределить память (дать размер памяти)
Функция DOS 49H: Освободить блок распределенной памяти
Функция DOS 4aH: Сжать или расширить блок памяти

Xariec
09.04.2009, 21:02
airyashov, благодарю за список функций прерывания, однако никак не разберусь, как же выполнить поставленное условие в коде :(

airyashov
10.04.2009, 07:57
Мне не понятна первая часть фразы Установить стратегию "последний подходящий"

Xariec
10.04.2009, 08:47
airyashov, вот что смог найти:
Область памяти UMB

Функция DOS 58h — Считать/изменить стратегию выделения памяти
Ввод: АН = 58h
AL = 00h — считать стратегию
AL = 01h — изменить стратегию
ВХ = новая стратегия

биты 2 – 0:
00 — первый подходящий блок
01 — наиболее подходящий блок
11 — последний подходящий блок биты 4 – 3:
00 — обычная память
01 — UMB (DOS 5.0+)
10 — UMB, затем обычная память (DOS 5.0+)

AL = 02h — считать состояние UMB
AL = 03h — установить состояние UMB
ВХ = новое состояние: 00 — не используются, 01 — используются
Вывод: CF = 0, АХ = текущая стратегия для AL = 0, состояние UMB для AL = 2
CF = 1, AX = 01h, если функция не поддерживается (если не запущен менеджер памяти (например, EMM386) или нет строки DOS = UMB в CONFIG.SYS

Если программа изменяла стратегию выделения памяти или состояние UMB, она обязательно должна их восстановить перед окончанием работы.

Только зачем она и для чего в данный момент не имею ни малейшего понятия.

somewhere
10.04.2009, 09:38
"Последний подходящий блок" отличается от "Первого подходящего" только адресом блока. "Последний подходящий" будет находится в самом конце кучи, если конечно память не сильно фрагментирована. Не даром функция имеет номер 58h, а это уже говорит о том, что она не является основной и без нее жить можно. По умолчанию MS-DOS использует стратегию "Первый подходящий". Я с ходу даже не могу привести пример где бы ее могли использовать и кому она будет нужна. С UMB все понятно, но вот стратегия...

Xariec
12.04.2009, 21:07
Что имеется на данный момент, помогите довести до конца :confused:

.386
.MODEL COMPACT
.STACK 4096
.data

.code
main PROC
mov ah,58h ;Код функции
mov al,01h ;Код подфункции
mov bl,02h ;Установка стратегии
INT 21h

mov ah,48h ;Код функции
mov bx,16h ;Выделяем размер памяти объёмом 16П
INT 21h

mov ah,4aH ;Код функции
main ENDP
mov al,4ch
INT 21h
END main