· Начало · Отвђтить · Статистика · Поиск · FAQ · Правила · Установки · Язык · Выход · WASM.RU · Noir.Ru ·

 WASM Phorum —› WASM.ASSEMBLER —› Макросы .IF/.ELSEIF/.ELSE/.ENDIF vs CASE/SWITCH

Посл.отвђт Сообщенiе


Дата: Апр 3, 2004 16:47:54

Не секрет что использование макросов типа .IF/.ELSEIF/.ELSE/.ENDIF
в обработчике сообщений диалогового окна приводит к некрасивому коду,
но вот использование case/switch в C или CASE/OF в Delphi вполне
с этим справляется, код получается правильный без глупых прыжков
типа:
   jnz @F
   ......
@@:
   jmp @F
   ......
@@:
   xor eax, eax
   inc eax
   ret


Т.е. вместо того чтобы сразу прыгнуть на последнюю метку оно прыгает через
промежуточный jmp

Есть ли какие-нибудь удачные попытки сделать макросы типа case/switch
в masm32, может в fasm?


Дата: Апр 3, 2004 17:48:31 · Поправил: S_T_A_S_

Я макросы не писал, делаю табличку (по 6 байт на сообщ. но можно и меньше)
И юзаю примерно такой код (он один для всех окон):
macro	MSGH	message, handler
 {		dw	meesage
		dd	handler }

;;  создаем табличку:
MsgHandles:
MSGH	WM_PAINT,Window.WM_PAINT
MSGH	WM_CREATE,Window.WM_CREATE
MSGH	WM_WINDOWPOSCHANGING,Window.SetClientSize
dw	WM_NULL		;;  end of MSGH table

;;  обрабатываем сообщ.
	movzx	edx, WORD[uMsg]		;;  MS allows to use only WORD
	mov	eax, MsgHandles		;;  message table
@@:	movzx	ecx, WORD[eax+0]	;;  get element from table
	add	eax, 6		;;  next table element
	or	ecx, ecx		;;  if zero, the end. process default
	je	.WM_NULL
	cmp	ecx, edx		;;  check message
	jne	@b			;;  not our message
	call	[eax+2-6]	;;  call msg_handler
;;  predefined message handlers
.WM_NULL:
	jmp	[DefWindowProc]


Дата: Апр 3, 2004 18:12:00 · Поправил: Asterix

Ага, работаешь как оптимизирующий компилятор MSVC или Delphi, там тоже такое в начале, и идут условные джампы в нужные места, но мысль я понял, надо будет попробовать сделать подобное для диалогового окна, которое из шаблона в rc, хотя есть у меня и другие мысли как немного улучшить код при использовании .IF/.ENDIF не прибегая к переходу на чистый asm.


Дата: Апр 3, 2004 18:40:47

А что нельза что ли написать так

mov eax, uMsg
cmp eax, WM_PAINT
jnz @@1

...

cmp eax, WM_COMMAND
jnz @@2

...

Ведь чаще всего к окну приходят сообщения WM_PAINT, потом WM_COMMAND, а остальные изредка, зачем тогда эти таблицы?


Дата: Апр 3, 2004 18:57:48

Я вот такое пользую собственного изготовления (скорее для наглядности, чем ради оптимизации).
IF_MSG MACRO msg:REQ, do:REQ
      cmp eax, msg
      jz  do
ENDM

;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::

Wnd_OnDestroy proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM

option PROLOGUE:NONE
option EPILOGUE:NONE

WND_PROC_LOCAL dwLocal1:DWORD, dwLocal2:DWORD

	invoke PostQuitMessage, 0

	pop eax
	jmp eax							; jmp LeaveWndProc

option PROLOGUE:PROLOGUEDEF
option EPILOGUE:EPILOGUEDEF

Wnd_OnDestroy endp

;::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ::::::

WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM

WND_PROC_LOCAL

	push LeaveWndProc0
	mov eax, uMsg
	IF_MSG	WM_CREATE,		Wnd_OnCreate
	IF_MSG	WM_DESTROY,		Wnd_OnDestroy

	pop eax
	invoke DefWindowProc, hWnd, uMsg, wParam, lParam		
	ret
		
	LeaveWndProc0::
	xor eax, eax				; return FALSE
	LeaveWndProc::
	ret
	
WndProc endp


Про switch/case ищи тут http://board.win32asmcommunity.net/ темы

"What is impossible?Optimized switch/case? NOT!"
"Optimizing Switch/Case..."

И, кстати, тема организации цикла обработки сообщений там тоже измусолена основательно.


Дата: Апр 3, 2004 19:29:41 · Поправил: S_T_A_S_

Asterix
Тут же нет условных джампов (почти) :-?


[ dragon - зачем тогда эти таблицы? ]

Экономия памяти
Кроме того, если это немного модернизировать - хранить смещение адреса обработчика (2 байта) вместо адреса,
то можно экономить еще по 2 байта на сообщении (Delphi ?) :-)
Самое главное в таком подходе - можно наделать кучу таблиц для разных окошек, а обрабатывать будет один и тот же код.
Тот же код может обрабатывать и еще что-то, например нажатые клавиши.
Это старинный трюк, который сейчас широко используется в т.н. "ООП" :D


Дата: Апр 3, 2004 20:33:10

[ dragon: А что нельза что ли написать так]

Иногда так и пишу, но я же написал что не хотелось бы переходить в данном случае на чистый асм, здесь это не требуется, зачем забивать код лишними cmp/jz/jnz.


Дата: Апр 3, 2004 21:03:00

Asterix
Ну не знаю, я так вообще никогда не использую всякие .IF, .ELSE и др, если уж асм так асм и никаких высокоуровневых конструкций. Одно дело - макросы типа CCOUNTED_UNICODE_STRING(для строк UNICODE_STRING) а другое - это такие конструкции, к тому же они скрывают часть кода.


Дата: Апр 3, 2004 21:05:30

> к тому же они скрывают часть кода.

Не настолько значимую чтоб не скрывать ;-)


Дата: Апр 4, 2004 01:05:50

В проекте Fresh я изпользую вот что:
macro MessageList [message, msghandler] {
  forward
        dw message,msghandler - $ - 2
  common
        dd 0
}

;------------------------------------------------------
; proc JumpTo
; Searches for the message in the message table.
; Arguments:
;   ebx - message number to search in the table.
; Returns:
;   This procedure doesn't returns. It simply
;   jumps to the address from table or imediately
;   after the table if the message is not found.
;   in both cases esi = eip
; Uses:
;   eax, esi
;------------------------------------------------------
proc JumpTo
        begin
        pop     esi     ; get table address and remove return
                        ; address from the stack.
.loop:
        lodsd
        test    eax,eax
        jz      .exit

        cmp     bx, ax
        jne     .loop

        sar     eax, 16
        add     esi, eax
.exit:
        jmp     esi
endp



А изпользуеться вот так:
        mov     ebx, [wmsg]   ; ето собственно message
        call    JumpTo
        MessageList                     \
        WM_INITDIALOG,  .wminitdialog,  \
        WM_??????,      .???,           \
        WM_NOTIFY,      .wmnotify


Дата: Апр 4, 2004 02:09:29

JMP на метку медленнее чем просто 'провалиться' дальше по коду.
Так что вот это:
cmp eax, WM_xxx
je @@_1
cmp eax, WM_xxx
je @@_2
cmp eax, WM_xxx
je @@_3

лучше чем вот это:
cmp eax, WM_xxx
jne @@_chk_2

; handler #1
...

@@_chk_2:
cmp eax, WM_xxx
jne @@_chk_3

; handler #2
...

@@_chk_3:
cmp eax, WM_xxx
jne @@_chk_4

; handler #3
...

но наверное, лучший метод - через таблицу (как S_T_A_S_).

Кстати, в библиотеке AsmDev32 будет такой объект - динамический линейный вектор, который строится добавляя 32-битное значение и адрес обработчика. Далее, вызываем метод Route и происходит поиск значения и вызов обработчика. Там ещё передаётся LPARAM для самой функции обработчика (для универсальности - в Windows везде так). Кроме того, есть сортировка по значениям и бинарный поиск (если надо). В общем, наворочено...

Я понимаю, что это не самый эффективный подход, но чтобы получить что-то работающее - в самый раз, а оптимизировать надо после отладки.


Дата: Апр 4, 2004 17:44:28 · Поправил: Asterix

Суммировав всё вышесказанное, а также прочтенное на board.win32asmcommunity.net для себя я остановился на таком макросе увиденном у The Svin'а:
WM_CASE MACRO reg:REQ, msgs:REQ
 IRP msg, <msgs>
      cmp reg, WM_&msg
      je @&msg
 ENDM
ENDM


Применять так:
DlgProc proc hWnd, uMsg, wParam, lParam
  mov eax, uMsg
   WM_CASE eax, <INITDIALOG, COMMAND, CLOSE>
@r0:
   xor eax, eax
   ret
@INITDIALOG:
 .......................
   jmp @r1
@COMMAND:
   mov eax, wParam
 .......................
   jmp @r1
@CLOSE:
   invoke EndDialog, hWnd, 0
@r1:
   xor eax, eax
   inc eax
   ret
DlgProc endp


Powered by miniBB 1.6 © 2001-2002
Время загрузки страницы (сек.): 0.075