Вот есть такая ф-я, написанная в целях оптимизации Код (Text): function StrToInt ( Str : PChar ) : Cardinal; asm mov esi, eax //? xor eax, eax //? cdq @loop: lodsb sub al, 48 jb @done imul edx, 10 add edx, eax jmp @loop @done: mov eax, edx //? ret end; Но т.к. я совсем не знаток Asm'a, то неуверен насчет правильности строк помеченных "//?". Скажите пожайлуста, этот код не будет сбоить? Может есть еще более короткий вариант?
Еще меньше можно: http://twister.rootkits.ru/notes.php#n_smint2str (в название ссылки не смотри - влом править было)
Вообщето это и есть твой код, только слегка измененный, дабы использовать его в Delphi программах. Так как изменял я, то спрашиваю, правильно сделал али нет
function StrToInt ( Str : PChar ) : Cardinal; asm mov esi, Str xor eax, eax cdq @loop: lodsb sub al, 48 jb @done imul edx, 10 add edx, eax jmp @loop @done: mov Result, edx // всётки делфе.. лучше предостерегусь. ret end; вотак. кстате "SMALLEST STR2INT" - смелое заявление .)) я бы сказал, слишком.
В дельфи-программах нужна оптимизация по размеру вплоть до байта ?!! Лучше бы из дельфийской _ValLong выдрал бы кусок, исключив лишние проверки Нет, регистр esi нужно сохранять и восстанавливать при выходе из функции - а это лишних 2 байта, о ужо-о-с !!
Я писал так: (параметры через стек не передавал, а так - аргумент (указатель на строку) в esi, результат в edi... Еще один момент - я точно знал что отдаю число определенной разрядности, поэтому использовал loop и не использовал проверку валидности Код (Text): Str2Int proc xor eax,eax xor edi,edi mov ecx,SIZE_NUM nxt: lea edi,[edi*4+edi] lea edi,[edi*2+eax] lodsb xor eax,30h loop nxt ret Str2Int endp
Думать нужно немного прежде чем копи-пастить Ради 1-байтной тормозной lodsb тебе придется добавить еще 4 байта на mov\push\pop esi - итого 5 байт, хотя по простому достаточно 3 байт mov+inc. Плюс мелочная экономия на imul+add дает выигрыш в 1 байт по сравнению с двумя lea, но зато заметно тормознее особенно на P4. К тому же если экономить байты, то незачем юзать два перехода jb+jmp, если можно обойтись одним, переставив местами загрузку символа и вычисление результата Вот для примера простой вариант без мелочной экономии (ес-но без доп.проверок недопустимые символы, включая знак минус) Код (Text): function MyStrToInt(S:pChar):cardinal;register; //eax = S asm xor edx,edx xor ecx,ecx @@loop: lea ecx,[ecx+ecx*4] //ecx:=ecx*5 lea ecx,[edx+ecx*2] //ecx:=ecx*2+edx mov dl,[eax] inc eax sub dl,'0' jnc @@loop mov eax,ecx end;
А вообще в MASM в каталоге m32lib лежит прелюбопытнейший файл, называется atodw.asm Код (Text): atodw proc String:DWORD ; ---------------------------------------- ; Convert decimal string into dword value ; return value in eax ; ---------------------------------------- push esi push edi xor eax, eax mov esi, [String] xor ecx, ecx xor edx, edx mov al, [esi] inc esi cmp al, 2D jne proceed mov al, byte ptr [esi] not edx inc esi jmp proceed @@: sub al, 30h lea ecx, dword ptr [ecx+4*ecx] lea ecx, dword ptr [eax+2*ecx] mov al, byte ptr [esi] inc esi proceed: or al, al jne @B lea eax, dword ptr [edx+ecx] xor eax, edx pop edi pop esi ret atodw endp тока я б тут если не lodsb, то хотя бы movzx заюзал вместо mov
2 leo Спасибо. Про директиву компилятора register я совсем забыл... Эта кажется самое большая ошибка в этих 10 строках Видимо компилятор просто в процессе оптимизации делал все как надо. ( ибо на первый взгляд работало )
FakeMan В дельфях и так по умолчанию юзается register, иначе бы твоя функция вообще бы не работала. А "самая большая ошибка" - это затирание esi. По общему правилу можно изменять только eax, edx и ecx, а если юзаешь другие регистры, то их нужно сохранять и восстанавливать перед выходом из функции Twister Переставь imul+add в начало цикла и убери лишний jmp PS: Гордиться минимальным размером при нестандартной конвенции вызова - мягко говоря, не честно
Реверс асм кода на дельфе: Код (Text): {$APPTYPE CONSOLE} program test; function StrToInt (Str:PChar):Cardinal; var ch:^byte; begin Result := 0; ch := pointer(str); repeat Result := Result * 10 + (ch^-48); inc(ch); until ch^ = 0; end; begin writeln (integer(StrToInt ('1234567890'))); end. и как его оформил компиль: Код (Text): -.00401C7C: 33D2 xor edx,edx -.00401C7E: 03D2 add edx,edx -.00401C80: 8D1492 lea edx,[edx][edx]*4 -.00401C83: 0FB608 movzx ecx,b,[eax] -.00401C86: 83E930 sub ecx,030 ; -.00401C89: 03D1 add edx,ecx -.00401C8B: 40 inc eax -.00401C8C: 803800 cmp b,[eax],000 -.00401C8F: 75ED jne .000401C7E -.00401C91: 8BC2 mov eax,edx -.00401C93: C3 retn лепота