Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Низкоуровневое программирование > Assembler - Ассемблер (FASM, MASM, WASM, NASM, GoASM, Gas, RosAsm, HLA) и не рекомендуем TASM
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 16.07.2010, 04:35   #1
Пепел Феникса
Старожил
 
Аватар для Пепел Феникса
 
Регистрация: 28.01.2009
Сообщений: 21,000
По умолчанию реализация case.

как лучше всего реализовать case <чтото> of?(C++: switch(<чтото>))
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
Программа делает то что написал программист, а не то что он хотел.
Функции/утилиты ждут в параметрах то что им надо, а не то что вы хотите.
Пепел Феникса вне форума Ответить с цитированием
Старый 16.07.2010, 08:25   #2
p51x
Старожил
 
Регистрация: 15.02.2010
Сообщений: 15,709
По умолчанию

Мало информации для точного ответа. Например, компиляторы заменют это насравнения, таблицу переходов,...
p51x вне форума Ответить с цитированием
Старый 16.07.2010, 10:48   #3
Mikl___
Участник клуба
 
Регистрация: 11.01.2010
Сообщений: 1,139
По умолчанию

Пепел Феникса
Задача конструкции CASE заключается в проверке на равенство значения переменной var элементу из списка.
CASE <var> OF
<case A> (выполнить, если var = A)
<case B> (выполнить, если var = B)
. . .
<case N> (выполнить, если var = N)
<default> (выполнить, если нет соответствия)
END_CASE
На ассемблере конструкция CASE может быть реализована, по крайней мере, семью способами:
1) тупо, через повторяющиеся команды cmp и je.
2) через макрос
3) через высокоуровневые директивы .IF .ELSEIF .ELSE
4) через косвенные переходы или косвенный вызов процедур
5) через команду SCASD
6) через последовательное приближение
7) через имитацию команды XLAT
Рассмотрим подпрограмму, обрабатывающую только четыре сообщения: WM_CREATE=1, WM_DESTROY=2, WM_PAINT=0Fh и WM_TIMER=113h. Пусть сообщение WM_XX обрабатывается по адресу @@WM_XX.
первый способ очевиден.
Код:
cmp dword ptr Msg,WM_TIMER 
    je @@WM_TIMER
cmp dword ptr Msg,WM_PAINT
    je @@WM_PAINT
cmp dword ptr Msg,WM_CREATE
    je @@WM_CREATE
cmp dword ptr Msg,WM_DESTROY
    je @@WM_DESTROY
leave         
    jmp DefWindowProcA; обработка по умолчанию      
@@WM_DESTROY: 
. . .
@@WM_CREATE:
. . .
@@WM_PAINT:
. . .
@@WM_TIMER:
. . .
один из вариантов первого способа — заменить команду cmp на команду sub
Код:
mov eax,Msg
dec eax 
jz @@WM_CREATE    ;WM_CREATE=1
dec eax
jz @@WM_DESTROY    ;WM_CREATE+1=WM_DESTROY=2
sub eax,0Dh 
jz @@WM_PAINT    ;WM_DESTROY+0Dh=WM_PAINT=0Fh
sub eax,104h
jz @@WM_TIMER    ;WM_PAINT+104h=WM_TIMER=113h
mov esp,ebp        ;все сообщения, не обрабатываемые в функции 
      pop ebp        ;WndProc, направляются на обработку по умолчанию      
    jmp DefWindowProcA 
@@WM_DESTROY: 
. . .

Последний раз редактировалось Mikl___; 17.07.2010 в 08:15.
Mikl___ вне форума Ответить с цитированием
Старый 16.07.2010, 10:55   #4
Mikl___
Участник клуба
 
Регистрация: 11.01.2010
Сообщений: 1,139
По умолчанию

Способ второй. Используем макрос с IRP-блоком (Вы, конечно, мо жете, если захотите, написать другой макрос). Блоки повторения IRP имеют следующий вид: IRP p,<v1,…,vn>
<тело блока>
ENDM
Запись в уголках <v1,…,vn> это явно указываемые фактические параметры, p — некоторое имя, оно играет роль формального (фиктивного) параметра и используется в предложениях тела блока. Фактические параметры vi перечисляются через запятую, а вся их совокупность обязательно заключается в угловые скобки. Встретив IRP-блок, макрогенератор заменит блок на n копий тела блока (по одной копии на фактический параметр), причем в i-той копии все вхождения имени p заменятся на vi. Знак & указывает границу формального параметра, выделяет его из окружающего текста, но в окончательный текст программы не попадает. Если в теле блока повторения или макроса имеются комментарии (в конце каких-то предложений или как самостоятельные предложения), то они переносятся во все копии блока. Если комментарий полезен при описании самого блока повторения, но совершенно не нужен в его копиях — тогда комментарий начинают с двух точек с запятой — такие комментарии не копируются.
Код:
IRP CASE, <WM_TIMER, WM_PAINT, WM_CREATE, WM_DESTROY>;; последовательность вариантов
cmp dword ptr Msg, CASE;;вариант найден?
je @@&CASE
ENDM;;закончить макроописание
leave        ; обработка по умолчанию
    jmp DefWindowProcA      
@@WM_DESTROY: 
. . .
Способ третий. Пример использования директив ассемблера .IF .ELSEIF .ELSE .ENDIF:
Код:
.IF (Msg==WM_TIMER)
. . .            ;здесь обрабатывается сообщение WM_TIMER
.ELSEIF (Msg==WM_PAINT)
. . .            ;здесь обрабатывается сообщение WM_PAINT
.ELSEIF (Msg==WM_CREATE)
. . .            ;здесь обрабатывается сообщение WM_CREATE
.ELSEIF (Msg==WM_DESTROY)
. . .            ; здесь обрабатывается сообщение WM_DESTROY
.ELSE
 leave        
jmp DefWindowProcA; обработка по умолчанию
.ENDIF
И вариант с макросом, и вариант с .IF .ELSEIF .ELSE .ENDIF все равно будут оттранслированы в повторяющиеся команды CMP и JE
Способ четвертый. Налицо в программе очень много повторяющихся почти одинаковых фрагментов. Нельзя ли написать программу как-нибудь иначе? Чем различаются эти фрагменты программы? Разными операндами в команде CMP, разными адресами переходов или разными вызываемыми процедурами. Уберем операнды команды CMP в какой-нибудь регистр и исполь зуем для разных адресов переходов косвенный переход, а для разных вызываемых процедур — косвенный вызов процедуры.
Код:
;Таблица сообщений, которые обрабатывает процедура окна
MsgTable dd WM_PAINT, @@WM_PAINT, WM_TIMER, @@WM_TIMER, WM_CREATE, @@WM_CREATE, WM_DESTROY, @@WM_DESTROY, 0; Конец списка обязательно 0
. . .
;Вызов соответствующего обработчика
mov esi,offset MsgTable    ;устанавливаем в ESI адрес таблицы-диспетчера
a1:     mov eax,[esi]         ;устанавливаем в eax тип сообщения
    test eax,eax    ;это конец таблицы? Если да, то данное сообщение не
jz @@default; обрабатывается приложением - передаем управление Windows
    cmp eax,Msg
    jne a2    ;для данного сообщения не найден обработчик
add esi,4    ;устанавливаем в esi адрес обработки сообщения
jmp [esi]            ;передаем управление обработчику сообщения
a2:    add esi,8            ;перейдем к следующему сообщению
    jmp short a1    
@@default: leave        ;Обработчик не найден, возвращается значение,
jmp DefWindowProcA    ; которое дает стандартный обработчик
@@WM_DESTROY:

Последний раз редактировалось Mikl___; 17.07.2010 в 08:17.
Mikl___ вне форума Ответить с цитированием
Старый 16.07.2010, 10:55   #5
Mikl___
Участник клуба
 
Регистрация: 11.01.2010
Сообщений: 1,139
По умолчанию

Способ пятый. Используем команду SCASD с префиксом REPNE. Внесем в конец таблицы сообщений, которые обрабатывает процедура окна, адрес обработки по умолчанию, а в регистр ECX количество элементов в таблице сообщений минус один (компилятор подсчитает это число автоматически). Напомню, что команда SCASD сравнивает значение в регистре EAX с ячейкой памяти, локализуемой регистром EDI. Префикс REPNE не только заставляет циклически выполняться команду сканирования, пока ECX не станет равным 0, но и отслеживает состояние флага ZF. Как только содержимое в ячейке памяти совпадет со значением в регистре EAX, сканирование остановится. Регистр EDI будет указывать не на ячейку памяти, значение которой совпадает с регистром EAX, а на следующую ячейку. Сканирование также остановится, если содержимое регистра ECX станет равным 0. При этом в регистре EDI будет адрес метки @@default (адрес обработки по умолчанию)
Код:
;Таблица сообщений, которые обрабатывает процедура окна
MsgTable dd WM_PAINT, @@WM_PAINT, WM_TIMER, @@WM_TIMER, WM_CREATE, \ 
@@WM_CREATE, WM_DESTROY, @@WM_DESTROY, @@default
MsgCount = ($ - MSGTable - 4)/4
. . .
mov edi,offset MsgTable;устанавливаем в EDI адрес таблицы-диспетчера
mov eax,Msg
mov ecx,MsgCount;удвоенное количество обрабатываемых сообщений (4*2=8)
repne scasd        ;ищем сообщение и если найдем — передадим
jmp dword ptr [edi]        ; управление обработчику сообщения
@@default:     leave        ; если обработчик не найден, вызывается
      jmp DefWindowProcA ; обработка по умолчанию
@@WM_DESTROY:
По величине это, по-моему, самый короткий код функции обработки сообщений. Возникает вопрос: «а что произойдет, если адрес обработчика сообщения совпадет с номером сообщения?» Этого не может произойти, так как максимальный номер стандартных сообщений равен 400h, а 32-разрядная операционная система Windows отводит каждой программе свое адресное пространство размером около двух гигабайт, начиная с адреса 100000h. За границы своего адресного пространства задача выйти не может, так же, как никакая другая задача не может работать с данным пространством - этим и определяется автономность программы.
Способ шестой — последовательное приближение. Пусть у нас уже не 4 обрабатываемых сообщения, а 100. Тогда при использовании с первого по пятый способ мы должны будем последовательно сравнить до 100 значений, до тех пор пока не найдем искомое. Увеличим скорость обработки сообщений, которые Windows посылает Вашему приложению. Рассортируем номера обрабатываемых нашей программой сообщений по возрастанию, теперь разделим номера сообщений на две равные группы — 50 сообщений с меньшими номерами в одной группе, 50 сообщений с большими номерами в другой. После определения, к какой из групп сообщений принадлежит вновь поступившее сообщение, нам потребуется уже не 100, а только 50+1 сравнение. Разобьем каждую из образовавшихся групп с номерами сообщений еще на две подгруппы, и потребуется уже 25+2 сравнений, вместо 100. Продолжаем делить подгруппы с номерами сообщений, и получаем 13+3 вместо 100, затем 7+4, далее 4+5, и, наконец, 2+6, больше разбивать подгруппы не имеет смысла (дальше было бы 1+7, а это одно и то же, что и 2+6). То есть, в общем случае, если 2^(n-1) < N <= 2^n, то определить N можно не более чем за n+1 приближение. Заметьте, увеличение скорости обработки будет сопровождаться разрастанием кода программы.
Код:
mas        dd WM_CREATE, WM_DESTROY... WM_PAINT ;массив сообщений
        n = ($ - mas)/4
mas1        dd @@WM_CREATE, @@WM_DESTROY,...  @@WM_PAINT;массив адресов
...
        xor ecx,ecx            ;в ecx индекс первого элемента
        mov edx,n-1            ;в edx индекс последнего элемента
        mov eax,Msg
        cmp eax,WM_CREATE;сравниваем с минимальным элементом таблицы
        jb short @@default;если меньше, то обработка по умолчанию
        mov ebx,edx        ;создаем индекс центрального элемента
a1:        cmp ecx,edx        ;проверка ecx>edx на окончание поиска
    ja short @@default;проверены все элементы, обработка по умолчанию
        shr ebx,1    ;индекс центрального элемента равен (edx+ecx)/2
        cmp mas[ebx*4],eax    ;сравниваем с искомым значением
        jb a2            ;mas[ebx*4]<Msg
        je a3         ;mas[ebx*4]=Msg        
inc ebx        ;учтем только что проверенное значение
        mov ecx,ebx            ;изменяем нижнюю границу поиска
        add ebx,edx        ;создаем индекс центрального элемента
        jmp short a1        ;переходим к следующему элементу
a2:        dec ebx        ;учтем только что проверенное значение
mov edx,ebx            ;изменяем верхнюю границу поиска
        add ebx,ecx        ;создаем индекс центрального элемента
        jmp short a1        ;переходим к следующему элементу
@@default:    leave            ;искомое значение не найдено,
jmp DefWindowProc    ;обработка по умолчанию
a3:        jmp mas1[ebx*4]        ;искомое значение найдено
@@WM_CREATE: ...

Последний раз редактировалось Mikl___; 17.07.2010 в 08:19.
Mikl___ вне форума Ответить с цитированием
Старый 16.07.2010, 10:58   #6
Mikl___
Участник клуба
 
Регистрация: 11.01.2010
Сообщений: 1,139
По умолчанию

и т.д. извините, что цитирую самого себя подробнее здесь
Mikl___ вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
CASE drikusik# Помощь студентам 4 16.12.2009 15:22
for and case искандрик Помощь студентам 5 16.12.2009 14:50
Case Is nes@ Помощь студентам 0 18.11.2009 20:21