Поиск символа в строке

Тема в разделе "WASM.ASSEMBLER", создана пользователем ASMatik, 15 июл 2008.

  1. ASMatik

    ASMatik New Member

    Публикаций:
    0
    Регистрация:
    3 июл 2008
    Сообщения:
    27
    Вообщем написал функцию (юзаю MASM):
    Код (Text):
    1. ischr proc uses edi chr:BYTE,string:DWORD,len:DWORD
    2.     mov al, chr
    3.     mov ecx, len
    4.     xor edi, edi
    5.     next:
    6.         cmp byte ptr [string+edi], al
    7.         je found
    8.         inc edi
    9.         loop next
    10.         mov eax,0
    11.         jmp exit
    12.     found:
    13.         mov eax,1
    14.     exit:
    15.         ret
    16. 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 Ногами сильно не пинать, т.к. нахожусь только в процессе обучения асму)
     
  2. Osen

    Osen Рие

    Публикаций:
    0
    Регистрация:
    5 апр 2008
    Сообщения:
    283
    Адрес:
    Париж
    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
     
  3. ADim

    ADim New Member

    Публикаций:
    0
    Регистрация:
    6 май 2007
    Сообщения:
    28
    Лучше было бы:
    mov edi,string вместо xor edi,edi
    а в цикле cmp [edi],al вместо cmp byte ptr [string+edi], al

    Параметры передаются через стек, выражение [string+edi] будет преобразовано в [ebp+ххх+edi], а имеет в виду вовсе не это.
     
  4. ASMatik

    ASMatik New Member

    Публикаций:
    0
    Регистрация:
    3 июл 2008
    Сообщения:
    27
    Всем спасибо, особенно ADim. Как раз проблема-то и была в том, что надо было использовать косвенную адресацию.
    ToOsen
    По 3-му пункту немного не пойму, зачем юзать xor eax, eax + inc eax, если это сожрет больше тактов, чем mov eax,1???
     
  5. DEEP

    DEEP Андрей

    Публикаций:
    0
    Регистрация:
    27 апр 2008
    Сообщения:
    491
    Адрес:
    г. Владимир
    На всякий пожарный: вот вариант, более приспособленный для "длинных" строк. Сканирует сразу по 4 символа. Четырёхкратного прироста в скорости не обещаю, но 2,75 раза - запросто.

    Код (Text):
    1. IsChar proc _s:DWORD, _c:Byte, _l:DWORD;
    2.   MOV EAX, _s;
    3.   MOV DL, _c;
    4.   PUSH EBX;
    5.   PUSH EDI;
    6.   MOV DH, DL;
    7.   MOVZX ECX, DX;
    8.   SHL EDX, 16;
    9.   OR EDX, ECX;
    10.   MOV ECX, _l;
    11.   ADD ECX, 4;
    12.  
    13.   @loop:
    14.     ADD ECX, -4;
    15.     JL @nqlp;
    16.     MOV EBX, DWORD PTR [EAX+ECX];
    17.     XOR EBX, EDX;
    18.     LEA EDI, [EBX-01010101h];
    19.     NOT EBX;
    20.     AND EDI, EBX;
    21.     AND EDI, 80808080h;
    22.   JE @loop;
    23.  
    24.   POP EDI;
    25.   POP EBX;
    26.   MOV EAX, 1;
    27.   RET;
    28.  
    29.   @nqlp:
    30.   POP EDI;
    31.   POP EBX;
    32.   XOR EAX, EAX;
    33.   RET;
    34. IsChar endp;
     
  6. Osen

    Osen Рие

    Публикаций:
    0
    Регистрация:
    5 апр 2008
    Сообщения:
    283
    Адрес:
    Париж
    ASMatik
    Тактов одинакого, размер кода меньше.
     
  7. ASMatik

    ASMatik New Member

    Публикаций:
    0
    Регистрация:
    3 июл 2008
    Сообщения:
    27
    Спасибо DEEP. Сохранил твой код на всякий случай. Пока что мне не нужно по 4 символа сканить, но в будущем потребуется.
    ToOsen, почитал хэлп к masm. На .386 тактов от xor+inc больше, а на 486 mov eax, 1 выполняется всего за 1 такт. Кстати, намного ли уменьшится размер кода?
     
  8. censored

    censored New Member

    Публикаций:
    0
    Регистрация:
    5 июл 2005
    Сообщения:
    1.615
    Адрес:
    деревня "Анонимные Прокси"
    or eax, -1 ?
     
  9. AsmGuru62

    AsmGuru62 Member

    Публикаций:
    0
    Регистрация:
    12 сен 2002
    Сообщения:
    689
    Адрес:
    Toronto
    REP SCASB
     
  10. Phantom_84

    Phantom_84 New Member

    Публикаций:
    0
    Регистрация:
    6 июн 2007
    Сообщения:
    820
    Действительно зачем что-то выдумывать, когда есть repne scasb
     
  11. ASMatik

    ASMatik New Member

    Публикаций:
    0
    Регистрация:
    3 июл 2008
    Сообщения:
    27
    Всем большое спасибо! ToPhantom_84 А выдумал я потому, что не дочитал до главы 7))) Пишу проект и заодно учусь асму по Юрию Магда (Ассемблер для процессоров Intel Pentium)
     
  12. Phantom_84

    Phantom_84 New Member

    Публикаций:
    0
    Регистрация:
    6 июн 2007
    Сообщения:
    820
    Желаю успехов в изучении ассемблера :)
     
  13. ASMatik

    ASMatik New Member

    Публикаций:
    0
    Регистрация:
    3 июл 2008
    Сообщения:
    27
    Спасибо. Все, тему можно закрывать, проблема решена с помощью repne scasb
     
  14. ASMatik

    ASMatik New Member

    Публикаций:
    0
    Регистрация:
    3 июл 2008
    Сообщения:
    27
    Вот, кстати, кому интересно, готовая реализация:
    Код (Text):
    1. ischr proc uses edi chr:BYTE,string:DWORD,len:DWORD
    2.     mov al, chr
    3.     mov edi, string
    4.     mov ecx, len
    5.     repne scasb
    6.     je found
    7.     xor eax, eax
    8.     jmp exit
    9.     found:
    10.         mov eax, 1
    11.     exit:
    12.         ret
    13. ischr endp
    Функция принимает 3 параметра: chr - искомый символ, string - строка, в которой ищем, len - длина строки
    Возвращаемые значения:
    0 - если сивол в строке не найден
    1 - символ найден
     
  15. DEEP

    DEEP Андрей

    Публикаций:
    0
    Регистрация:
    27 апр 2008
    Сообщения:
    491
    Адрес:
    г. Владимир
    -del-
     
  16. 2FED

    2FED New Member

    Публикаций:
    0
    Регистрация:
    20 фев 2008
    Сообщения:
    1.002
    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 если ничо не найдено, или адрес найденого элемента
     
  17. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    ASMatik
    Код (Text):
    1. xor eax,eax
    2. ...
    3. repne scasb
    4. sete al
    5. ret
     
  18. DEEP

    DEEP Андрей

    Публикаций:
    0
    Регистрация:
    27 апр 2008
    Сообщения:
    491
    Адрес:
    г. Владимир
    leo
    Тогда уж ещё и MOVZX EAX, chr - освобождаемся от XOR.
     
  19. ASMatik

    ASMatik New Member

    Публикаций:
    0
    Регистрация:
    3 июл 2008
    Сообщения:
    27
    Всем спасибо.
    В итоге код уменьшился до:
    Код (Text):
    1. ischr proc uses edi chr:BYTE,string:DWORD,len:DWORD
    2.     movzx eax, chr
    3.     mov edi, string
    4.     mov ecx, len
    5.     repne scasb
    6.     sete al
    7.     ret
    8. ischr endp
    2FED - спасибо конечно за реализацию, но пока у меня стоит простая задача - ограничить ввод точек в контроле EDIT, собственно мне только и нужно, что проанализировать строку на наличие символа ".", а уж в какой позиции он стоит уже не важно
     
  20. 2FED

    2FED New Member

    Публикаций:
    0
    Регистрация:
    20 фев 2008
    Сообщения:
    1.002
    А если ещё и вызывать процедур так

    Код (Text):
    1. ischr proc
    2.     repne scasb
    3.     sete al
    4.     ret
    5. ischr endp
    6.  
    7. ...
    8.  
    9. mov edi,string
    10. mov ecx,len
    11. movzx eax, chr
    12. call ischr
    к стате это будет не чёть не дленее чем командами push полюс к тому передача параметров через регистры быстрее. ну и в конце концов можно прийти к выводу что процедура воабще не нужна так как она сводится к

    repne scasb
    sete al

    которые можно и так вставить в код избавившись от лишних прыжков =)