Как я могу найти последние 0 на массиве в Nasm? - PullRequest
0 голосов
/ 27 марта 2019

Я пишу код, чтобы найти последние 0 в массиве.

По сути, мне нужно переместить новое значение в «вершину» каждого массива, если оно имеет только нули, оно помещает его вend, и если он находит другое значение, он помещает его в последний 0 (я рассматриваю мои массивы как груды).

Пока что моя подпрограмма по большей части работает нормально, но иногда она перезаписывает значение, которое мне не нужно (вместо того, чтобы получить первое значение, отличное от 0, оно принимает следующее).Вот код, который я использовал, чтобы получить «вершину» массива.

TOP:
    xor ecx,ecx
    xor ebx,ebx
TOP_FOR:                    
    mov bx,word[eax+ecx*2]   ;eax has the pointer of the array
    cmp ecx,n                ;n is the array's length
    je END_TOP
    inc ecx
    cmp bx,0
    je TOP_FOR
                    ;here i get the direction of the first value different
END_TOP:            ;from 0 but in my code i need the last 0, so
    dec ecx         ;i decrease ecx (result of this subrutine)
    ret

Например, если я поставлю массив с 0,2, я ожидаю ecx = 0, но с этим вводом получим 1.

  • С массивом 1,2Я получаю 0 (это то, что я хочу)
  • с массивом 0,0 Я получаю 1 (что я хочу, снова)

Edit: попытался запустить цикл на n-1, и это дает мне еще более странные результаты.

TOP:
    xor ecx,ecx
    ;xor ebx,ebx
    mov ecx,n-1
TOP_FOR:
    ;mov bx,word[eax+ecx*2]
    cmp word[eax+ecx*2],0
    je FIN_TOPE
    dec ecx
    cmp ecx,0
    jne TOP_FOR

END_TOP:

    ret

1 Ответ

1 голос
/ 27 марта 2019

Ваша логика полностью обратная. Ваше условие цикла cmp / je выходит из цикла, когда вы найдете первый ненулевой. (И вы уже увеличили ECX после загрузки, но перед проверкой).

Итак, после вашего цикла ECX = индекс элемента после первого ненулевого элемента.

У вас есть как минимум 2 варианта:

  • запомнить последний увиденный 0 в другом регистре и использовать его в конце цикла
  • loop в обратном направлении , начиная с ECX = n-1, и выйти из цикла напервый ноль.(Или на dec ecx, производящем 0.)

Один из них, очевидно, более эффективен и проще, чем другой.: P

Я оставлю на ваше усмотрение решение проблем off-by-1, но, вероятно, вы хотите иметь проверку ecx < n или ecx >= 0 в нижней части цикла, например dec ecx / jge TOP_FOR.т. е. цикл do{}while(--i).


Кроме того, обычно EBX является регистром, сохраняющим вызов.Вам не нужно использовать его вообще, хотя.cmp word [eax + ecx*2], 0 отлично работает.

Также в вашем текущем коде вы читаете 2 байта после конца массива.потенциально неисправен, если это было в конце страницы.(Однако вы не используете его, так что это не проблема правильности, кроме этого.) Вы используете ECX в качестве индекса перед проверкой, если он слишком большой!Эта проблема исчезнет, ​​если вы просто используете память, немедленно cmp.

Кроме того, обычно увеличение указателя более эффективно.После цикла вы можете вычесть и сдвинуть вправо, чтобы получить индекс.

...