leo Кстати у меня скорость обработки инфы в сотни раз быстрее, чем подобные в моей области сделаны на Васиках.
Valentin Дело не столько в самом Васике или асме, сколько в неверном (бездумном) использовании стандартных средств языка. Если для твоей задачи бесхитростно юзать склейку динамических строк в виде S=S+S1, то тормоза будут по любому - и в васике, и в дельфях и С++, т.к. при достаточно большой длине S будут возникать перераспределения памяти под S с копированием больших объемов данных из одного блока памяти в другой - а тут тебе и тормоза чтения\записи из-за невлезания данных в кэш процессора и отказы страниц и т.п., и все это может повторяться десятки-сотни раз. А если сразу выделить под результирующую строку блок памяти достаточно большого размера, то ничего этого не будет и скорость склейки будет значительно выше - и в си, и в дельфях, и в васике (если юзать функции АПИ CopyMemory и т.п.)
leo Согласен. Я заметил ч-з прогрессбар что с накоплением строки работа идет все медленнее и медленее, понятно. А как указать на конец буфера?? Если Вы опытный в памяти, приведите пожалуqста пример накопления строки в памяти. В ссылках на Ваши посты есть примеры, но архивы 7z не открываюся/
Valentin 1. Разово выделяешь 10-мегабайтовй буффер через VirtualAlloc 2. Указатель сохраняешь в 2 переменные: указатель на буффер и в указатель на конец строки 3. Делаешь самописную MylstrcpyA, которая после копирования, будет возвращать указатель на конец строки 4. Формируешь строку Думаю, это будет самый быстрый вариант Пример Код (Text): /*---------------------------copy string------------------------------------- char* MylstrcpyA(char* dest, char* src) { char* pointer; _asm { mov esi, [src] mov edi, [dest] copy_string: movsb cmp byte ptr [esi], 0 jnz copy_string mov byte ptr [edi], 0 mov [pointer], edi } return pointer; } Код (Text): /*---------------------------allocate memory------------------------------------- buff = VirtualAlloc(0, 0A00000h, MEM_COMMIT, PAGE_READWRITE); //buffer eos = (PCHAR)buff; //end of string /*---------------------------sample---------------------------------------------- eos = MylstrcpyA(eos, S1); eos = MylstrcpyA(eos, S2); eos = MylstrcpyA(eos, S3); eos = MylstrcpyA(eos, Sn); Дальше уже идет железная оптимизация, например замена опкодов на более быстрые, спаривающиеся, и.д. и.т.п. Я этих тонкостей не знаю, в этом поможет leo PS: если вдруг нужно онулить всю 10-мегабайтную строку, то делаешь так: Код (Text): eos = (char*)buff; eos[0] = 0;
в этом случае строка не будет завершена 0 считаю необходимым сделать как минимум mov byte ptr [edi],0 после цикла - мало ли как строка еще будет использоваться
int2e Я работаю на МАSM32, нужен перевод: пока так: ; ---------------------------copy string------------------------------------- MylstrcpyA proc destWORD, srcWORD) LOCAL pointerWORD mov esi, [src] mov edi, [dest] copy_string: movsb cmp byte ptr [esi], 0 jnz copy_string mov byte ptr [edi], 0 mov [pointer], edi ret MylstrcpyA endp Теперь с памятью: ;---------------------------allocate memory------------------------------------- buff dd ? eos dd ? invoke VirtualAlloc,0, 0A00000h, MEM_COMMIT, PAGE_READWRITE mov buff,eax = (PCHAR)buff; //end of string ========= как здесь??? ;---------------------------sample---------------------------------------------- invoke MylstrcpyA, addr eos, addr S1
Код (Text): MylstrcpyA proc dest:DWORD, src:DWORD mov esi, [src] mov edi, [dest] copy_string: movsb cmp byte ptr [esi], 0 jnz copy_string mov byte ptr [edi], 0 mov eax, edi ret MylstrcpyA endp Код (Text): buff dd ? eos dd ? invoke VirtualAlloc,0, 0A00000h, MEM_COMMIT, PAGE_READWRITE mov [buff],eax mov [eos], eax Код (Text): invoke MylstrcpyA, dword ptr [eos], addr S1 mov [eos], eax invoke MylstrcpyA, dword ptr [eos], addr S2 mov [eos], eax ;... invoke MylstrcpyA, dword ptr [eos], addr Sn mov [eos], eax
int2e Код (Text): copy_string: movsb cmp byte ptr [esi], 0 jnz copy_string mov byte ptr [edi], 0 ; mov eax, edi - так не получается, строка уже в eax ret теперь после выполнения: Код (Text): invoke MylstrcpyA, dword ptr [eos], addr S1 mov [eos], eax в [eos] -строки нет. И еще, где учавствует buff -?
По стандарту, функции возвращают значение в еах. Там строки и не будет. Там будет указатель на нее Если тебе понадобится освободить память либо занулить массив, то тут пригодится buff
А как реализовать функцию, которая будет накапливать строки в динамически увеличиваемом буфере Есть код, но он почему-то не работает: ========================================= Код (Text): .686 .model flat, stdcall option casemap:none include \masm32\include\kernel32.inc include \masm32\include\windows.inc include \masm32\include\user32.inc includelib \masm32\lib\kernel32.lib includelib \masm32\lib\user32.lib Mylstrcpy PROTO : WORD, :WORD .data STROKA db "HELLO", 0 ; Исходная строка .data? buffS dd ? ; Указатель на буфер eos dd ? ; Указатель на конец строки в буфере .code start: ; Инициализация buffS с помощью VirtualAlloc invoke VirtualAlloc, NULL, 1, MEM_COMMIT, PAGE_READWRITE mov [buffS], eax mov [eos], eax ; eos указывает на начало buffS ; Добавляем строку "HELLO" invoke Mylstrcpy, dword ptr [eos], addr STROKA ; Теперь buffS содержит "HELLO" ; eos указывает на конец строки ; Добавляем ещё одну строку invoke Mylstrcpy, dword ptr [eos], addr STROKA ; Теперь buffS содержит "HELLOHELLO" ; eos указывает на конец строки ; invoke MessageBox, NULL, buffS, NULL, MB_OK OR MB_ICONWARNING OR MB_SYSTEMMODAL ; Освобождаем память invoke VirtualFree, [buffS], 0, MEM_RELEASE invoke MessageBox, NULL, [buffS], NULL, MB_OK OR MB_ICONWARNING OR MB_SYSTEMMODAL ; Завершение программы invoke ExitProcess, 0 Mylstrcpy proc public uses esi edi ebx dest:lol: WORD, src:lol: WORD ; dest — указатель на конец строки в buffS ; src — указатель на новую строку ; Загружаем указатели mov esi, src ; esi = адрес новой строки mov edi, dest ; edi = текущий конец строки в buffS ; Находим длину новой строки (src) xor ecx, ecx ; Счётчик длины mov ebx, esi ; Сохраняем начало src find_src_len: cmp byte ptr [ebx], 0 ; Проверяем конец строки je src_len_found inc ecx ; Увеличиваем счётчик inc ebx ; Переходим к следующему символу jmp find_src_len src_len_found: ; Находим текущую длину buffS mov ebx, [buffS] ; ebx = начало buffS mov edx, edi ; edx = текущий конец строки sub edx, ebx ; edx = длина текущей строки в buffS ; Вычисляем новый размер буфера add edx, ecx ; edx = текущая длина + длина новой строки inc edx ; Учитываем нулевой символ ; Выделяем новую память с помощью VirtualAlloc invoke VirtualAlloc, NULL, edx, MEM_COMMIT, PAGE_READWRITE test eax, eax ; Проверяем, удалось ли выделить память jz fail ; Если нет, завершаем с ошибкой ; Копируем данные из старого буфера в новый mov ecx, edi ; ecx = текущий конец строки sub ecx, [buffS] ; ecx = длина текущей строки mov esi, [buffS] ; esi = начало старого буфера mov edi, eax ; edi = начало нового буфера rep movsb ; Копируем данные ; Освобождаем старый буфер mov dword ptr [buffS],0 ; invoke VirtualFree, [buffS], 0, MEM_RELEASE ; Обновляем указатель на буфер mov [buffS], eax invoke MessageBox, NULL, [eax], NULL, MB_OK OR MB_ICONWARNING OR MB_SYSTEMMODAL ; Копируем новую строку в конец buffS mov edi, eax ; edi = новый адрес buffS add edi, edx ; edi = конец текущей строки dec edi ; Убираем нулевой символ copy_loop: movsb ; Копируем байт из [esi] в [edi] cmp byte ptr [esi], 0 ; Проверяем конец строки jne copy_loop ; Добавляем нулевой символ в конец mov byte ptr [edi], 0 ; Обновляем eos mov [eos], edi fail: ret Mylstrcpy endp end start
VirtualAlloc для кусочков произвольного размера лучше не использовать. Попробуйте написать через GetProcessHeap/HeapAlloc/HeapReAlloc VirtualAlloc надо использовать для работы с блоками кратными 4096 и выравненными на такие же адреса. Если нужен накопитель для строк, тогда достаточно простой функции копирования, которая возвращает количество скопированных символов. Код (ASM): ; fasm1 без макросов, i386, частичный кусок struc _buf_data { label . .ptr dd ? .end dd ? .handle dd ? } ; блок данных buffer _buf_data str_hello db "HELLO", 0 ; секция кода ; ... lea ebx, [buffer] call _buf_init lea esi, [str_hello] call _strpush call _buf_free ; ... _buf_init: ; in { ebx = указатель на переменную, которая содержит указатель на буфер для накопления в структуре из трех полей (не инициализированный) }, out { eax = указатель на буфер } .init_size = 65536 ; 64 Кб начальный размер буфера virtual at ebx .buf _buf_data end virtual call [GetProcessHeap] push .init_size push HEAP_ZERO_MEMORY push eax call [HeapAlloc] lea ecx, [eax + .init_size] mov [.buf.handle], eax mov [.buf.end], ecx mov [.buf.ptr], eax retn _buf_free: ; in { ebx = указатель на переменную, которая содержит указатель на буфер для накопления в структуре из трех полей (инициализированный) } virtual at ebx .buf _buf_data end virtual call [GetProcessHeap] push dword [.buf.handle] push HEAP_ZERO_MEMORY push eax call [HeapFree] xor eax, eax mov [.buf.handle], eax mov [.buf.end], ecx mov [.buf.ptr], eax retn _strcopy: ; in { esi = исходная строка; edi = буфер для копирования; ecx = указатель на конец буфера (по достижении этого значения edi будет ошибка нехватки памяти) }, out { eax = количество байт без учета 0; cf = признак ошибки } pushfd push esi mov edx, edi cld jmp _strcopy_start _stdcopy_loop: cmp edi, ecx jae _strcopy_out_of_memory movsb _strcopy_start: cmp byte [esi], 0 jnz _stdcopy_loop mov eax, edi movsb sub eax, edx pop esi popfd cld retn _strcopy_out_of_memory: mov edi, edx xor eax, eax pop esi popfd std retn _strpush: ; in { esi = исходная строка; ebx = указатель на переменную, которая содержит указатель на буфер для накопления в структуре из трех полей }, out { eax = количество байт } virtual at ebx .buf _buf_data end virtual push edi _strpush_retry: mov edi, [.buf.ptr] mov ecx, [.buf.end] call _strcopy jnc _strpush_done call [GetProcessHeap] mov edx, [.buf.handle] mov edi, [.buf.end] sub edi, edx add edi, 4096 push edi push edx push HEAP_REALLOC_IN_PLACE_ONLY push eax call [HeapReAlloc] add edi, [.buf.handle] mov [.buf.end], edi jmp _strpush_retry _strpush_done: inc eax add [.buf.ptr], eax pop edi retn
Кроме стандартного размера страницы 4096 байт (4 КБ), в некоторых архитектурах Windows также поддерживаются большие страницы размером 2 МБ и 1 ГБ.