1

0 から 100 までのすべての数字を出力するプログラムを作成しています。変数 (この場合は変数counter) が保持する桁数を見つける必要があります。

これが私のコードです:

SECTION .data
len EQU 32

SECTION .bss
counter resd len 
digit1 resd len
digit2 resd len
digit3 resd len

SECTION .text
GLOBAL _start
_start:
nop

Print:
mov eax, 4
mov ebx, 1
mov ecx, counter
mov edx, len
int 80h 

Set:
mov BYTE [counter], 1

Divide:
; HERE IS WHERE I NEED TO FIND THE LENGTH OF THE VARIABLE COUNTER
; initial division
mov ax, [counter]   ; number we want to print
mov ch, 10    ; we divide by ten to siphon digits
div ch        ; divide our number by 10

; al now has 11, ah has 1
mov dh, ah             ; save the remainder in dh
xor ah,ah
mov ch, 10             ; refill ch with the divisor
div ch                 ; al now has 1, ah now has 1

Move:                     ; now to move our digits to a printable state
mov [digit1], dh      ; first digit is in edx
mov [digit2], ah
mov [digit3], al

Adjust:
add BYTE [digit1], '0'
add BYTE [digit2], '0'
add BYTE [digit3], '0'

Print:
mov eax, 4
mov ebx, 1
mov ecx, digit1
mov edx, len
int 80h

mov eax, 4
mov ebx, 1
mov ecx, digit2
mov edx, len
int 80h

mov eax, 4
mov ebx, 1
mov ecx, digit3
mov edx, len
int 80h

Exit:
mov eax, 1
mov ebx, 0
int 80h

変数カウンターを何回分割するか、また何桁を印刷するかを知るために、長さを見つける必要があります。

どのくらいの長さかを調べるにはどうすればよいですか?

前もって感謝します

4

3 に答える 3

1

アキは例を挙げました!「-S」スイッチを使用してコンパイルし、コンパイラがそれをどのように処理するかを確認します。ただし、あまり役に立たない場合があります。:)

あなたは桁数を計算する方法を尋ねます。div数字を数えるためだけに商がゼロになるまでループ全体を実行するコード(有名な本の著者から!)を見たことがあります。次に、彼は別のdivループを実行して'日を見つけます!> 10、> 100、>1000などを実行すると機能します。しかし、なぜあなたは知る必要があるのですか?div商がゼロになるまで続けて、桁数を数えることができます。div実際、商を9と比較することで、 (非常にdiv遅いです!)を節約できます。もしそうならbe、最後の桁はalです。追加divのIMOを実行する方が簡単です。:)

余り/桁は「間違った」順序で取得されます。私はこれに対処する3つの方法を知っています。私が「最も簡単」だと思うのは、スタックに'emをプッシュしてカウントし、保存/印刷したい順序で' emをポップして、前後に'0'を追加することです。

もう1つの方法は、バッファの「後方」から開始して「前方」に移動することです。これがアキの頌歌です。C互換コードの場合、ゼロで終了する文字列を返すことは問題ありませんが、sys_writeはゼロで終了する文字列を認識しないため、長さを知りたいと考えています。(問題ありません。「zstring」の長さを見つけることができます)これはバッファの先頭に到達しないことに注意してください。「C互換」コードを気にしない場合は、「バッファ内のどこに到達したか」と長さの両方を返すことができます。おそらく、sys_writeが必要とする場所ecxと場所です。edxまたは、バッファの先頭までスペースを埋めることができます。右寄せされた数値は、列に印刷すると見栄えがします。:)

さらに別の方法は、先に進んで'emをバッファに「後方」に配置し、最後に「逆文字列」を実行することです。

これらの方法はどれも非常に高速ではありません。div遅い、期間!私はTerjeMathieson(「光速」ソリューションの専門家)からの使用しないコードを「持っています」が、divそれを理解しておらず、使用していません。お急ぎの場合は、さまざまな最適化マニュアルに記載されています。:)

100に制限しても、それほど多くは得られません。完全な32ビットレジスタを使用してルーチンを作成するのも同じくらい簡単で(おそらく簡単です)、CPUはそれに慣れています。負の数を処理する必要がある場合、それはもう少し複雑です。このあたりで例が見つからない場合は、Nasmフォーラムでいくつか見つけることができますが、実際に試してみるのは興味深い演習です。

うーん...見て...「多すぎる」メモリを予約すると、プログラムが「肥大化」する可能性がありますが、害はありません。「不十分な」メモリを予約するのはバグです!ですから、あなたは「多すぎる」側で誤りを犯すのが得策です。まだ...

SECTION .data
len EQU 32

SECTION .bss
counter resd len 
digit1 resd len
digit2 resd len
digit3 resd len

... 128バイトのバッファを使用し、その32バイトを1桁/文字で印刷するのは大変なことのようです。:)

最高、フランク

于 2012-10-14T14:03:59.690 に答える
1

範囲内の数値については、0..100次のような疑似アセンブラーを使用して、境界で比較します。

    mov ax, [counter]

    mov cx, 3             ; default length
    cmp ax, 100           ; >= 100, use 3
    bge done

    dec cx                ; set length to 2
    cmp val, 10           ; >= 10, use 2
    bge done

    dec cx                ; set length to 1

done:
                          ; cx now holds the digit count.

実際には 999 まで処理できますが、範囲を広げたい場合は、100 の前にさらに条件チェックを追加することもできます。

于 2012-10-14T07:27:12.783 に答える
0

通常、これは内部バッファーで行われます (実際にはスタックが行います:)

Y=X mod 10 (または Y=X mod base)、X=X div base を、X=0 になるまで分割します (そして、各 mod Y をプッシュします) 分割数をカウントし、スタック C の回数から各結果をポップします出力ストリームに書き込みます。

void print_number(int eax, int ebx) {  // ebx = base, eax = number
   int ecx = 0;
   do {
      edx = eax % ebx;
      eax = eax / ebx;
      push(edx);
      ecx++;
   } while (eax);

   while (ecx) {
      pop (eax);
      putch(eax+'0');
      ecx--;
   }
}

ポイントは、必要な回数だけ正確に分割することです。

もう少し最適化されたものは [ここでも C で自分の思考を促す] です...

void print_number(int a, int base) {
     char string[10];
     static *ptr = string+9;  // points to the last char of string
     *ptr--=0;                // write ending ASCII Zero.
     *ptr='0';
     while (a) {
          *--ptr= '0'+(a % base);  // works for base = 2-10
          a/=base;
     }
     printf("%s",ptr);
}

なぜこれが機能するのか (または機能しないのか) わかりますか?

于 2012-10-14T07:33:47.193 に答える