2016-12-01 14 views
0

私はアセンブリに新しく、宿題をやろうとしています、インデックスの値の代わりに配列のインデックス位置を印刷する方法を知りたい、ポインタとしてESIを使用しています。ここでは配列は0と1で埋められており、1のインデックスのみを出力したいと思います。 サンプルアレイ[1 | 1 | 0 | 0 | 1]どのようにインデックス位置を印刷するには

PRINT: 
    mov eax,[esi] 
    cmp eax,1 
    je Show 
    add esi,4 
    loop PRINT 
Show: 
    call WriteDec 
    call Crlf 
    loop Show 

出力は、(1 2 5)又は(0 1 4)であるべきです。おかげさまで

+5

Count。 'esi'でやっているのと同じですが、0または1から始めて1ずつ進みます。 –

+1

配列の定義方法は表示されません。アセンブリの定義では、データの構造はコードそのものよりも重要な場合があります。定義がなければ、あなたのコードがそのまま動作するかどうかを知ることは難しく、あなたに答えるために変更することも、すでにバグを含んでいるかどうかを知ることもできます(例えば、 'mov eax、[esi]'は疑わしいです。 esi、4'それは大丈夫です)。 [mcve]はアセンブリで非常に重要です。 – Ped7g

+0

しかし、もう一度考えてみると、この問題は、コードなしではもっと意味があります。解決法のコードよりもメソッド/原則、解決方法を尋ねるなら、宿題は有効です。 – Ped7g

答えて

0

いずれかのカウンタを追加します。

mov ebx,1   ; index counter, first element = 1 
PRINT: 
    mov eax,[esi] 
    cmp eax,1 
    jne noShow 

    mov eax,ebx   
    call WriteDec 
    call Crlf 
noShow: 
    add esi,4 
    inc ebx   ; increase counter 
    loop PRINT 

又は(ESI = ARRAY + 4 *指数を想定)ESIからそれを計算

PRINT: 
    mov eax,[esi] 
    cmp eax,1 
    jne noShow 

    mov eax, esi  ; load position in index 
    sub eax, ARRAY  ; remove starting position of the array 
    shr eax, 2   ; divide it by 4, to get index position 
    call WriteDec 
    call Crlf 

noShow: 
    add esi,4 
    loop PRINT 

(PS:で間違っていた固定ループロジックを質問)

(PSS:私は、コードの気圧をテストすることはできません、私は仕事でね)

+0

OPのポストでコードが既に間違っています...最後の 'ループショー 'は意味をなさない。あなたの最初の変種では、それを修正するのは簡単ではないので、悪化します。なぜなら、あなたは 'ebx'を1つのパスでのみ更新するからです。 – Ped7g

+3

'shr eax、4'にタイプミスがあります。 2 –

+0

oopsである必要があります。あなたが正しい。ありがとう、修正済み – Tommylee2k

1

あなたがで開始する必要があります@ MargaretBloomのアイデアは、また、それがアルゴリズムで他のいくつかのエラーを修正する必要があります、カウント:

  • あなたは2 loop持って、問題が最初loop端は、コードの次のブロックが実行されるとき、あり、そしてeaxが印刷されます再び無限ループが始まります。
  • loopShowにジャンプしますが、PRINTにジャンプする必要があります。 1の値が検出されたときにインデックスがインクリメントされないよう
  • あなたは、je Showesiが増加している、esiは前をインクリメントする必要があります。

私は位置あなたは(あなたが他のレジスタを使用することができます)表示したいようediを使用する、のは、それらのほとんどの問題を修正しましょう:

mov edi, 0  ;◄■■ THIS IS THE POSITION YOU WANT TO DISPLAY (1,2,3,...). 
PRINT:  
    mov eax,[esi] 
    add esi,4  ;◄■■ INCREMENT INDEX HERE. 
    inc edi   ;◄■■ INCREASE POSITION (1,2,3,...). 
    cmp eax,1 
    je Show 
    loop PRINT 
    jmp Finish  ;◄■■ SKIP NEXT BLOCK WHEN FINISH. 
Show: 
    mov eax, edi ;◄■■ DISPLAY POSITION. 
    call WriteDec 
    call Crlf 
    loop PRINT  ;◄■■ JUMP TO PRINT, NOT TO SHOW. 

Finish: 
0

どのように...インデックス位置配列の... ESIとしてのポインタ

最初に配列の定義が重要です。連続する要素からなる単純なフラット配列特定の要素のインデックスはあなたが関与する2つのポインタからそれを計算する逆にすることができますEDIアドレスが指す取得するには(これはESIでまだ元の開始のアレイポインタが必要です!):

mov eax,edi 
sub eax,esi  ; eax = (element_pointer - array_pointer) 
; divide eax by <size_of_element> 

; for example your OP code example suggest 
; the array element size is DWORD = 4B 
; then the division/4 can be done simply: 
; shr eax,2 

; for byte arrays there's no need to divide the address 
; difference, eax already contains index, as BYTE size = 1B 

; for other element sizes, which are *not* power-of-two 
; (you can't divide the difference by simply shifting it right) 
; it may be more efficient to address them through separate index 
; or do the: imul/mul (1/el_size) || idiv/div el_size 
; (when there's no way to avoid it) 

; after division the eax contains 0, 1, ... index. 

場合、要素の大きさ(2の累乗ではない)、または構造が簡単ではない(リンクされたリストなので、2つのポインタの違いが要素のインデックスと相関しない)場合、インデックスを個別にカウントすることができます。それでも、インデックスを取得するたびにインデックスのmul element_sizeを避けるため、2つを混在させる価値があるかもしれません。したがって、ポインタを使ってアドレッシングし、インデックスを必要とするものに対してのみ使用されるインデックスを個別にカウントしてください。

また、1からインデックスを付けることもできますが、プログラマー以外の人間が出力しない限り、避けることにします。ほとんどのASM/C/C++プログラマは、インデックス開始が当然0 how-pointer-mathは私の最初の例で動作します)。

; stolen from Toommylee2k, then modified to focus on my explanation 

    xor ebx,ebx   ; first index will be 1 (!) 
    ; so I initialized ebx = 1 - 1 = 0, because 
    ; I will increment it at beginning of loop 

    ; for indexing from 0 the ebx should be initialized to -1 

loop_start: 
    ; update index first, so you can't miss it when branching later 
    lea ebx,[ebx+1] ; ebx = ebx+1 without flags modification 

    ; since *here* "ebx" works as "index", contains "1" for first item 

    ; do whatever you want with pointers, like "esi" in your sample code 
    ; ... 

    ; move to next element of array (avoids multiplication) 
    add esi,size_of_element 
    ; although `imul` on modern CPU will perform quite close to `add` 
    ; so when multiplication is unavoidable, go for it. 

    ; the division on the other hand still costs very likely more 
    ; than having separate register/variable for index counting 

    ; loop till ecx is zero (in much faster way than "loop") 
    dec ecx 
    jnz loop_start 
    ; "loop" is very slow due to historic reasons, to improve compatibility 

そして最後の伸長、素子サイズはの一つである[1、2、4、8]、あなたはで動作するように拡張されたx86のアドレッシング・モードを使用することができます "0、1、..."純粋なポインタの代わりにインデックス:

mov ebx,7 ; index "7" = 8th element of array 
lea esi,[array_of_words] ; array pointer 

; addressing through index, supported directly by CPU for size 2 
mov ax,[esi + ebx*2]  ; complex x86 addressing allows this 

; here ax = 8 
... 

.data 
array_of_words: 
    dw 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 

ループ内のインデックスを使用すると、これが最適な解決策になる可能性があります。要素のインデックスがまれにしか必要ない場合は、通常は純粋なポインタが最適です。

関連する問題