Вообщем написал функцию (юзаю MASM): Код (Text): ischr proc uses edi chr:BYTE,string:DWORD,len:DWORD mov al, chr mov ecx, len xor edi, edi next: cmp byte ptr [string+edi], al je found inc edi loop next mov eax,0 jmp exit found: mov eax,1 exit: ret ischr endp На входе принимает chr - символ, который ищем, string - указатель на строку, len - длина строки. Функция по идее должна возвращать 1 если символ в строке найден, и 0 если не найден. Использую функцию в WndProc (WindowsXP) контрола EDIT: LOCAL p[255] :BYTE ... invoke GetWindowText, hWnd, addr p, 255 invoke ischr, '.', addr p, eax .if (!eax) ... GetWindowText возвращает длину строки, p - массив строки(если можно так назвать), '.' - символ, который ищем. По идее все это должно работать так: при вводе в мой EDIT символа '.', вызываем GetWindowText (для этого же EDIT'a) и проверяем, есть ли еще точки в строке, если есть, тогда отменяем ввод, если нет, то можно вводить. Но в реале получается полная ерунда: точек можно вводить только определенное количество и другие глюки. Подскажите, что не так в этом коде? PS Ногами сильно не пинать, т.к. нахожусь только в процессе обучения асму)
ASMatik 1) При кодинге на winapi никогда не передавай байты в функции. Юзай DWORD всегда + movzx если надо получить символ. Иначе могут быть проблемы со стеком. 2) Сам цикл поиска черезчур. Юзай строковую инструкцию cmpsb. 3) Вместо mov eax,0 пиши xor eax, eax / sub eax, eax. Вместо mov eax,1 пиши xor eax, eax + inc eax
Лучше было бы: mov edi,string вместо xor edi,edi а в цикле cmp [edi],al вместо cmp byte ptr [string+edi], al Параметры передаются через стек, выражение [string+edi] будет преобразовано в [ebp+ххх+edi], а имеет в виду вовсе не это.
Всем спасибо, особенно ADim. Как раз проблема-то и была в том, что надо было использовать косвенную адресацию. ToOsen По 3-му пункту немного не пойму, зачем юзать xor eax, eax + inc eax, если это сожрет больше тактов, чем mov eax,1???
На всякий пожарный: вот вариант, более приспособленный для "длинных" строк. Сканирует сразу по 4 символа. Четырёхкратного прироста в скорости не обещаю, но 2,75 раза - запросто. Код (Text): IsChar proc _s:DWORD, _c:Byte, _l:DWORD; MOV EAX, _s; MOV DL, _c; PUSH EBX; PUSH EDI; MOV DH, DL; MOVZX ECX, DX; SHL EDX, 16; OR EDX, ECX; MOV ECX, _l; ADD ECX, 4; @loop: ADD ECX, -4; JL @nqlp; MOV EBX, DWORD PTR [EAX+ECX]; XOR EBX, EDX; LEA EDI, [EBX-01010101h]; NOT EBX; AND EDI, EBX; AND EDI, 80808080h; JE @loop; POP EDI; POP EBX; MOV EAX, 1; RET; @nqlp: POP EDI; POP EBX; XOR EAX, EAX; RET; IsChar endp;
Спасибо DEEP. Сохранил твой код на всякий случай. Пока что мне не нужно по 4 символа сканить, но в будущем потребуется. ToOsen, почитал хэлп к masm. На .386 тактов от xor+inc больше, а на 486 mov eax, 1 выполняется всего за 1 такт. Кстати, намного ли уменьшится размер кода?
Всем большое спасибо! ToPhantom_84 А выдумал я потому, что не дочитал до главы 7))) Пишу проект и заодно учусь асму по Юрию Магда (Ассемблер для процессоров Intel Pentium)
Вот, кстати, кому интересно, готовая реализация: Код (Text): ischr proc uses edi chr:BYTE,string:DWORD,len:DWORD mov al, chr mov edi, string mov ecx, len repne scasb je found xor eax, eax jmp exit found: mov eax, 1 exit: ret ischr endp Функция принимает 3 параметра: chr - искомый символ, string - строка, в которой ищем, len - длина строки Возвращаемые значения: 0 - если сивол в строке не найден 1 - символ найден
ASMatik FindByte proc uses edi ecx edx mem:dword,b:dword,count:dword invoke lstrlen,mem mov ecx,eax mov edi,mem jmp nxt next: dec count nxt: mov eax,b cld repne scasb mov eax,edi xor edx,edx test ecx,ecx cmovz eax,edx test eax,eax jz exit cmp count,0 jnz next exit: ret FindByte endp mem - указатель на блок памяти в котором надо искать b - собсно байт который ищем count - какой по сщёту байт ищём Возвращает 0 если ничо не найдено, или адрес найденого элемента
Всем спасибо. В итоге код уменьшился до: Код (Text): ischr proc uses edi chr:BYTE,string:DWORD,len:DWORD movzx eax, chr mov edi, string mov ecx, len repne scasb sete al ret ischr endp 2FED - спасибо конечно за реализацию, но пока у меня стоит простая задача - ограничить ввод точек в контроле EDIT, собственно мне только и нужно, что проанализировать строку на наличие символа ".", а уж в какой позиции он стоит уже не важно
А если ещё и вызывать процедур так Код (Text): ischr proc repne scasb sete al ret ischr endp ... mov edi,string mov ecx,len movzx eax, chr call ischr к стате это будет не чёть не дленее чем командами push полюс к тому передача параметров через регистры быстрее. ну и в конце концов можно прийти к выводу что процедура воабще не нужна так как она сводится к repne scasb sete al которые можно и так вставить в код избавившись от лишних прыжков =)