Suche…


Bemerkungen

Das Konvertieren von Strings in Ganzzahlen ist eine der häufigsten Aufgaben.

Hier zeigen wir Ihnen, wie Sie Dezimalzeichenfolgen in Ganzzahlen konvertieren.

Psuedo-Code dafür ist:

function string_to_integer(str):
    result = 0
    for (each characters in str, left to right):
        result = result * 10
        add ((code of the character) - (code of character 0)) to result
    return result

Der Umgang mit hexadezimalen Zeichenfolgen ist etwas schwieriger, da Zeichencodes normalerweise nicht fortlaufend sind, wenn mehrere Zeichentypen wie Ziffern (0-9) und Alphabete (af und AF) verwendet werden. Zeichencodes sind in der Regel fortlaufend, wenn es sich nur um einen Typ von Zeichen handelt (wir behandeln hier Ziffern), sodass wir uns nur mit Umgebungen befassen, in denen Zeichencodes für Ziffern fortlaufend sind.

IA-32-Assembly, GAS, cdecl-Aufrufkonvention

# make this routine available outside this translation unit
.globl string_to_integer

string_to_integer:
    # function prologue
    push %ebp
    mov %esp, %ebp
    push %esi

    # initialize result (%eax) to zero
    xor %eax, %eax
    # fetch pointer to the string
    mov 8(%ebp), %esi

    # clear high bits of %ecx to be used in addition
    xor %ecx, %ecx
    # do the conversion
string_to_integer_loop:
    # fetch a character
    mov (%esi), %cl
    # exit loop when hit to NUL character
    test %cl, %cl
    jz string_to_integer_loop_end
    # multiply the result by 10
    mov $10, %edx
    mul %edx
    # convert the character to number and add it
    sub $'0', %cl
    add %ecx, %eax
    # proceed to next character
    inc %esi
    jmp string_to_integer_loop
string_to_integer_loop_end:

    # function epilogue
    pop %esi
    leave
    ret

Dieser Code im GAS-Stil konvertiert die als erstes Argument angegebene dezimale Zeichenfolge, die vor dem Aufruf dieser Funktion auf den Stack geschrieben wird, in Ganzzahl und gibt sie über %eax . Der Wert von %esi wird gespeichert, weil er ein Register für sicheres Speichern ist und verwendet wird.

Überlauf / Umbruch und ungültige Zeichen werden nicht geprüft, um den Code zu vereinfachen.

In C kann dieser Code folgendermaßen verwendet werden (vorausgesetzt, unsigned int und Zeiger unsigned int sind 4 Byte lang):

#include <stdio.h>

unsigned int string_to_integer(const char* str);

int main(void) {
    const char* testcases[] = {
        "0",
        "1",
        "10",
        "12345",
        "1234567890",
        NULL
    };
    const char** data;
    for (data = testcases; *data != NULL; data++) {
        printf("string_to_integer(%s) = %u\n", *data, string_to_integer(*data));
    }
    return 0;
}

Hinweis: In einigen Umgebungen müssen zwei string_to_integer im Assemblycode in _string_to_integer (Unterstrich hinzufügen) geändert werden, damit C-Code verwendet werden kann.

MS-DOS, TASM / MASM-Funktion zum Lesen einer vorzeichenlosen 16-Bit-Ganzzahl

Liest eine vorzeichenlose 16-Bit-Ganzzahl von der Eingabe.

Diese Funktion verwendet den Interrupt-Service Int 21 / AH = 0Ah zum Lesen einer gepufferten Zeichenfolge.
Durch die Verwendung einer gepufferten Zeichenfolge kann der Benutzer überprüfen, was er eingegeben hat, bevor er zur Verarbeitung an das Programm übergeben wird.
Es werden bis zu sechs Ziffern gelesen (65535 = 2 16 - 1 hat sechs Ziffern).

Neben der Standardkonvertierung von Zahl zu Zahl erkennt diese Funktion auch ungültige Eingabe und Überlauf (Zahl zu groß für 16 Bit).

Rückgabewerte

Die Funktion gibt die in AX gelesene Zahl zurück. Die Flags ZF , CF , OF , ob die Operation erfolgreich abgeschlossen wurde und warum.

Error AXT ZF CF VON
Keiner Die 16-Bit-Ganzzahl einstellen Nicht eingestellt Nicht eingestellt
Ungültige Eingabe Die teilweise konvertierte Zahl bis zur letzten gültigen Stelle Nicht eingestellt einstellen Nicht eingestellt
Überlauf 7fffh Nicht eingestellt einstellen einstellen

Mit dem ZF können gültige und ungültige Eingaben schnell voneinander unterschieden werden.

Verwendungszweck

call read_uint16
jo _handle_overflow            ;Number too big (Optional, the test below will do)
jnz _handle_invalid            ;Number format is invalid

;Here AX is the number read

Code

;Returns:
  ;
  ;If the number is correctly converted:
  ;   ZF = 1, CF = 0, OF = 0
  ;   AX = number
  ;
  ;If the user input an invalid digit:
  ;   ZF = 0, CF = 1, OF = 0
  ;   AX = Partially converted number
  ;
  ;If the user input a number too big
  ;   ZF = 0, CF = 1, OF = 1
  ;   AX = 07fffh
  ;
  ;ZF/CF can be used to discriminate valid vs invalid inputs
  ;OF can be used to discrimate the invalid inputs (overflow vs invalid digit)
  ;
  read_uint16:
    push bp   
    mov bp, sp

    ;This code is an example in Stack Overflow Documentation project.
    ;x86/Converting Decimal strings to integers


    ;Create the buffer structure on the stack

    sub sp, 06h                ;Reserve 6 byte on the stack (5 + CR)
    push 0006h                 ;Header

    push ds
    push bx
    push cx
    push dx

    ;Set DS = SS

    mov ax, ss
    mov ds, ax                           
                  

    ;Call Int 21/AH=0A

    lea dx, [bp-08h]            ;Address of the buffer structure
    mov ah, 0ah
    int 21h

    ;Start converting

    lea si, [bp-06h]
    xor ax, ax
    mov bx, 10
    xor cx, cx

   _r_ui16_convert:

    ;Get current char

    mov cl, BYTE PTR [si]
    inc si

    ;Check if end of string

    cmp cl, CR_CHAR
    je _r_ui16_end                      ;ZF = 1, CF = 0, OF = 0
   
    ;Convert char into digit and check

    sub cl, '0'
    jb _r_ui16_carry_end                ;ZF = 0, CF = 1, OF = X -> 0
    cmp cl, 9
    ja _r_ui16_carry_end                ;ZF = 0, CF = 0 -> 1, OF = X -> 0


    ;Update the partial result (taking care of overflow)

    ;AX = AX * 10
    mul bx

    ;DX:AX = DX:AX + CX
    add ax, cx
    adc dx, 0
       
    test dx, dx
   jz _r_ui16_convert            ;No overflow
   
    ;set OF and CF
    mov ax, 8000h
    dec ax                           
    stc

   jmp _r_ui16_end                      ;ZF = 0, CF = 1, OF = 1
    
   _r_ui16_carry_end:

    or bl, 1                ;Clear OF and ZF
    stc                     ;Set carry
 
    ;ZF = 0, CF = 1, OF = 0

   _r_ui16_end:
    ;Don't mess with flags hereafter!

    pop dx
    pop cx
    pop bx
    pop ds

    mov sp, bp

    pop bp
    ret

    CR_CHAR EQU 0dh

NASM-Portierung

Um den Code auf NASM zu portieren, entfernen Sie das PTR Schlüsselwort aus den Speicherzugriffen (z. B. mov cl, BYTE PTR [si] wird zu mov cl, BYTE [si] )

MS-DOS, TASM / MASM-Funktion zum Drucken einer 16-Bit-Zahl in binär, quaternär, oktal, hexadezimal

Drucken Sie eine Zahl in binär, quaternär, oktal, hexadezimal und mit einer Zweierpotenz

Alle Basen, die eine Zweierpotenz sind, wie die binäre (2 1 ), quaternäre (2 2 ), oktale (2 3 ), hexadezimale (2 4 ) Basis, haben eine ganzzahlige Anzahl von Bits pro Ziffer 1 .
Um also jede Ziffer 2 einer Ziffer abzurufen, brechen wir einfach die Zahl-Intro-Gruppe von n Bits, beginnend mit dem LSb (rechts).
Für die quaternäre Basis wird beispielsweise eine 16-Bit-Zahl in Gruppen von zwei Bits aufgeteilt. Es gibt 8 solcher Gruppen.
Nicht alle Potenzen von zwei Basen haben eine ganzzahlige Anzahl von Gruppen, die auf 16 Bit passen. Zum Beispiel hat die oktale Basis 5 Gruppen von 3 Bits, die 3 · 5 = 15 von 16 Bits ausmachen, wodurch eine Teilgruppe von 1 Bit 3 übrig bleibt.

Der Algorithmus ist einfach, wir isolieren jede Gruppe mit einer Verschiebung, gefolgt von einer UND- Verknüpfung.
Diese Prozedur funktioniert für jede Gruppengröße oder mit anderen Worten für jede Basisleistung von zwei.

Um die Ziffern in der richtigen Reihenfolge anzuzeigen, beginnt die Funktion mit der Isolation der höchstwertigen Gruppe (ganz links). Dabei ist es wichtig zu wissen: a) wie viele Bits Da eine Gruppe ist und b) die Bitposition S ganz links Gruppe beginnt
Diese Werte werden vorberechnet und in sorgfältig erstellten Konstanten gespeichert.

Parameter

Die Parameter müssen auf den Stapel gelegt werden.
Jeder ist 16 Bit breit.
Sie werden in Push-Reihenfolge angezeigt.

Parameter Beschreibung
N Die zu konvertierende Zahl
Base Die zu verwendende Basis wird mit den Konstanten BASE2 , BASE4 , BASE8 und BASE16
Führende Nullen drucken Wenn Null, werden keine nicht signifikanten Nullen gedruckt, andernfalls. Die Zahl 0 wird jedoch als "0" gedruckt

Verwendungszweck

push 241
push BASE16
push 0
call print_pow2              ;Prints f1

push 241
push BASE16
push 1
call print_pow2              ;Prints 00f1

push 241
push BASE2
push 0
call print_pow2              ;Prints 11110001

Hinweis für TASM-Benutzer : Wenn Sie die mit EQU definierten EQU nach dem Code setzen, der sie verwendet, aktivieren Sie den Mehrfachdurchlauf mit dem Flag /m von TASM oder Sie überschreiben die Vorwärtsreferenzbedingung .

Code

;Parameters (in order of push):
;
;number
;base (Use constants below)
;print leading zeros
print_pow2:
 push bp
 mov bp, sp

 push ax
 push bx
 push cx
 push dx
 push si
 push di

 ;Get parameters into the registers

 ;SI = Number (left) to convert
 ;CH = Amount of bits to shift for each digit (D)
 ;CL = Amount od bits to shift the number (S)
 ;BX = Bit mask for a digit

 mov si, WORD PTR [bp+08h]
 mov cx, WORD PTR [bp+06h]            ;CL = D, CH = S

 ;Computes BX = (1 << D)-1
 
 mov bx, 1
 shl bx, cl
 dec bx

 xchg cl, ch              ;CL = S, CH = D

_pp2_convert:
 mov di, si
 shr di, cl
 and di, bx         ;DI = Current digit

 or WORD PTR [bp+04h], di             ;If digit is non zero, [bp+04h] will become non zero
                      ;If [bp+04h] was non zero, result is non zero
 jnz _pp2_print                       ;Simply put, if the result is non zero, we must print the digit

 
 ;Here we have a non significant zero
 ;We should skip it BUT only if it is not the last digit (0 should be printed as "0" not
 ;an empty string)

 test cl, cl
 jnz _pp_continue


_pp2_print:
 ;Convert digit to digital and print it

 
 mov dl, BYTE PTR [DIGITS + di]
 mov ah, 02h
 int 21h


_pp_continue:
 ;Remove digit from the number

 sub cl, ch
jnc _pp2_convert

 pop di
 pop si
 pop dx
 pop cx
 pop bx
 pop ax

 pop bp
 ret 06h

Daten

This data must be put in the data segment, the one reached by `DS`.

DIGITS    db    "0123456789abcdef"

;Format for each WORD is S D where S and D are bytes (S the higher one)
;D = Bits per digit  --> log2(BASE)
;S = Initial shift count --> D*[ceil(16/D)-1]

BASE2    EQU    0f01h
BASE4    EQU    0e02h
BASE8    EQU    0f03h
BASE16    EQU    0c04h

NASM-Portierung

Um den Code auf NASM zu portieren, entfernen Sie das PTR-Schlüsselwort aus den Speicherzugriffen (z. B. mov si, WORD PTR [bp+08h] wird zu mov si, WORD PTR [bp+08h] ).

Funktion erweitern

Die Funktion kann problemlos auf jede Basis bis zu 2 255 erweitert werden , obwohl jede Basis über 2 16 die gleiche Zahl druckt, da die Anzahl nur 16 Bit beträgt.

So fügen Sie eine Basis hinzu:

  1. Definieren Sie eine neue Konstante BASEx wobei x 2 n ist .
    Das untere Byte mit dem Namen D ist D = n .
    Das obere Byte, genannt S , ist die Position der höheren Gruppe in Bits. Es kann berechnet werden als S = n · (~ 16 / n - 1).
  2. Fügen Sie der Zeichenfolge DIGITS die erforderlichen Ziffern DIGITS .

Beispiel: Hinzufügen der Basis 32

Wir haben D = 5 und S = 15, also definieren wir BASE32 EQU 0f05h .
Wir fügen dann sechzehn weitere Ziffern hinzu: DIGITS db "0123456789abcdefghijklmnopqrstuv" .

Es sollte klar sein, dass die Ziffern durch Bearbeiten der Zeichenfolge DIGITS geändert werden DIGITS .


1 Wenn B eine Basis ist, hat es B- Ziffern pro Definition. Die Anzahl der Bits pro Ziffer beträgt somit log 2 ( B ). Bei Zweierpotenzen vereinfacht sich dies auf log 2 (2 n ) = n, was per Definition eine ganze Zahl ist.

2 In diesem Zusammenhang wird implizit angenommen, dass die betrachtete Basis eine Potenz von zwei Basis 2n ist .

3 Damit eine Basis B = 2 n eine ganzzahlige Anzahl von Bitgruppen hat, muss dies n | sein 16 ( n teilt 16). Da der einzige Faktor in 16 2 ist, muss es sein, dass n selbst eine Zweierpotenz ist. Also hat B die Form 2 2 k oder äquivalent log 2 ( log 2 ( B )) muss eine ganze Zahl sein.

MS-DOS, TASM / MASM, Funktion zum Drucken einer 16-Bit-Zahl in Dezimalzahlen

Eine 16-Bit-Zahl ohne Vorzeichen wird dezimal ausgegeben

Der Interrupt-Dienst Int 21 / AH = 02h wird zum Drucken der Ziffern verwendet.
Die Standardumwandlung von Zahl zu Zahl wird mit dem div Befehl ausgeführt, der Dividend ist anfangs die höchste Leistung von zehn passenden 16 Bits (10 4 ) und wird bei jeder Iteration auf niedrigere Leistungen reduziert.

Parameter

Die Parameter werden in Push-Reihenfolge angezeigt.
Jeder ist 16 Bit.

Parameter Beschreibung
Nummer Die vorzeichenlose 16-Bit-Zahl, die in Dezimalzahlen gedruckt werden soll
führende Nullen anzeigen Wenn 0 keine nicht signifikanten Nullen gedruckt werden, sind sie andernfalls. Die Zahl 0 wird immer als "0" gedruckt.

Verwendungszweck

push 241
push 0
call print_dec          ;prints 241

push 56
push 1
call print_dec          ;prints 00056

push 0
push 0
call print_dec          ;prints 0

Code

;Parameters (in order of push):
;
;number
;Show leading zeros
print_dec:
 push bp
 mov bp, sp

 push ax
 push bx
 push cx
 push dx

 ;Set up registers:
 ;AX = Number left to print
 ;BX = Power of ten to extract the current digit
 ;DX = Scratch/Needed for DIV
 ;CX = Scratch

 mov ax, WORD PTR [bp+06h]
 mov bx, 10000d
 xor dx, dx

_pd_convert:     
 div bx                           ;DX = Number without highmost digit, AX = Highmost digit
 mov cx, dx                       ;Number left to print

 ;If digit is non zero or param for leading zeros is non zero
 ;print the digit
 or WORD PTR [bp+04h], ax
 jnz _pd_print

 ;If both are zeros, make sure to show at least one digit so that 0 prints as "0"
 cmp bx, 1
 jne _pd_continue

_pd_print:

 ;Print digit in AL

 mov dl, al
 add dl, '0'
 mov ah, 02h
 int 21h

_pd_continue:
 ;BX = BX/10
 ;DX = 0

 mov ax, bx
 xor dx, dx
 mov bx, 10d
 div bx
 mov bx, ax

 ;Put what's left of the number in AX again and repeat...
 mov ax, cx

 ;...Until the divisor is zero
 test bx, bx
jnz _pd_convert

 pop dx
 pop cx
 pop bx
 pop ax

 pop bp
 ret 04h

NASM-Portierung

Um den Code auf NASM zu portieren, entfernen Sie das Schlüsselwort PTR aus den Speicherzugriffen (z. B. mov ax, WORD PTR [bp+06h] wird zu mov ax, WORD [bp+06h] )



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow