Recherche…


Remarques

La conversion de chaînes en nombres entiers est l'une des tâches courantes.

Ici, nous allons montrer comment convertir des chaînes décimales en nombres entiers.

Le code Psuedo pour ce faire est:

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

Traiter les chaînes hexadécimales est un peu plus difficile car les codes de caractères ne sont généralement pas continus lorsque vous traitez plusieurs types de caractères tels que les chiffres (0-9) et les alphabets (af et AF). Les codes de caractères sont généralement continus lorsque vous traitez un seul type de caractères (nous traiterons ici des chiffres), nous ne traiterons donc que des environnements dans lesquels les codes de caractères pour les chiffres sont continus.

IA-32 assemblage, GAS, convention d'appel cdecl

# 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

Ce code de type GAS convertira la chaîne décimale donnée en premier argument, qui est insérée dans la pile avant d’appeler cette fonction, en entier et la renverra via %eax . La valeur de %esi est enregistrée car elle est appelée registre de sauvegarde et est utilisée.

Les débordements / enveloppements et les caractères non valides ne sont pas vérifiés pour simplifier le code.

Dans C, ce code peut être utilisé comme ceci (en supposant que unsigned int et les pointeurs ont une longueur de 4 octets):

#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;
}

Remarque: dans certains environnements, deux string_to_integer dans le code d'assemblage doivent être remplacés par _string_to_integer (ajouter un trait de soulignement) afin de le laisser fonctionner avec le code C.

Fonction MS-DOS, TASM / MASM pour lire un entier non signé 16 bits

Lire un entier non signé 16 bits à partir de l'entrée.

Cette fonction utilise le service d'interruption Int 21 / AH = 0Ah pour lire une chaîne mise en mémoire tampon.
L'utilisation d'une chaîne en mémoire tampon permet à l'utilisateur de revoir ce qu'il a tapé avant de le transmettre au programme pour traitement.
Jusqu'à six chiffres sont lus (65535 = 2 16 - 1 à six chiffres).

En plus d' effectuer la conversion standard du numérique au numéro de cette fonction détecte également une entrée non valide et le débordement (nombre trop gros pour tenir 16 bits).

Valeurs de retour

La fonction renvoie le numéro lu dans AX . Les drapeaux ZF , CF , OF indiquent si l'opération s'est terminée avec succès ou non et pourquoi.

Erreur HACHE ZF CF DE
Aucun L'entier 16 bits Ensemble Pas encore défini Pas encore défini
Entrée invalide Le nombre partiellement converti, jusqu'au dernier chiffre valide rencontré Pas encore défini Ensemble Pas encore défini
Débordement 7fffh Pas encore défini Ensemble Ensemble

Le ZF peut être utilisé pour distinguer rapidement les entrées valides des données invalides.

Usage

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

Portage NASM

Pour porter le code sur NASM, supprimez le mot-clé PTR des accès mémoire (par exemple mov cl, BYTE PTR [si] devient mov cl, BYTE [si] )

Fonction MS-DOS, TASM / MASM pour imprimer un nombre 16 bits en binaire, quaternaire, octal, hexadécimal

Imprimer un nombre en binaire, quaternaire, octal, hexadécimal et une puissance générale de deux

Toutes les bases qui ont une puissance de deux, comme les bases binaire (2 1 ), quaternaire (2 2 ), octale (2 3 ) et hexadécimale (2 4 ), ont un nombre entier de bits par chiffre 1 .
Ainsi, pour récupérer chaque chiffre 2 d'un nombre, nous cassons simplement le groupe d'introduction numérique de n bits à partir du LSb (le droit).
Par exemple, pour la base quaternaire, nous divisons un nombre de 16 bits par groupes de deux bits. Il y a 8 de ces groupes.
Toutes les puissances de deux bases ne comportent pas un nombre entier de groupes correspondant à 16 bits; Par exemple, la base octale a 5 groupes de 3 bits qui représentent 3 · 5 = 15 bits sur 16, laissant un groupe partiel de 1 bit 3 .

L'algorithme est simple, nous isolons chaque groupe avec un décalage suivi d'une opération AND .
Cette procédure fonctionne pour chaque taille de groupe ou, en d'autres termes, pour toute puissance de base de deux.

Afin de montrer les chiffres dans le bon ordre, la fonction commence par isoler le groupe le plus significatif (le plus à gauche), il est donc important de savoir: a) combien de bits D un groupe est et b) la position de bit S le groupe commence
Ces valeurs sont précalculées et stockées dans des constantes soigneusement conçues.

Paramètres

Les paramètres doivent être poussés sur la pile.
Chacun est large de 16 bits.
Ils sont affichés par ordre de poussée.

Paramètre La description
N Le nombre à convertir
Base La base à utiliser exprimée en utilisant les constantes BASE2 , BASE4 , BASE8 et BASE16
Imprimer des zéros en tête Si zéro, aucun zéros non significatif n'est imprimé, sinon ils le sont. Le nombre 0 est imprimé comme "0" si

Usage

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

Note aux utilisateurs TASM: Si vous mettez les constantes définies avec EQU après le code qui les utilise, activez plusieurs passes avec le /m drapeau de TASM ou vous aurez besoin de référence avant remplacement.

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

Les données

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

Portage NASM

Pour porter le code sur NASM, supprimez le mot-clé PTR des accès mémoire (par exemple mov si, WORD PTR [bp+08h] devient mov si, WORD PTR [bp+08h] )

Extension de la fonction

La fonction peut être facilement étendue à n'importe quelle base jusqu'à 2 255 , bien que chaque base au-dessus de 2 16 imprime le même nombre que le nombre est seulement 16 bits.

Ajouter une base:

  1. Définissez une nouvelle constante BASExx est 2 n .
    L'octet inférieur, nommé D , est D = n .
    L'octet supérieur, nommé S , est la position, en bits, du groupe supérieur. Il peut être calculé comme S = n · (⌈16 / n 1 - 1).
  2. Ajoutez les chiffres nécessaires à la chaîne DIGITS .

Exemple: ajout de la base 32

Nous avons D = 5 et S = 15, nous définissons donc BASE32 EQU 0f05h .
Nous ajoutons ensuite seize chiffres de plus: DIGITS db "0123456789abcdefghijklmnopqrstuv" .

Comme cela devrait être clair, les chiffres peuvent être modifiés en éditant la chaîne DIGITS .


1 Si B est une base, alors il a B chiffres par définition. Le nombre de bits par chiffre est donc log 2 ( B ). Pour la puissance de deux bases, cela simplifie log 2 (2 n ) = n qui est un entier par définition.

2 Dans ce contexte, on suppose implicitement que la base considérée est une puissance de deux bases 2 n .

3 Pour qu'une base B = 2 n ait un nombre entier de groupes de bits, il faut que n | 16 ( n divise 16). Puisque le seul facteur en 16 est 2, il faut que n soit lui-même une puissance de deux. Donc B a la forme 2 2 k ou, de manière équivalente, log 2 ( log 2 ( B )) doit être un entier.

MS-DOS, TASM / MASM, fonction pour imprimer un nombre 16 bits en décimal

Imprimer un nombre non signé 16 bits en décimal

Le service d'interruption Int 21 / AH = 02h est utilisé pour imprimer les chiffres.
La conversion standard à partir du numéro de référence numérique est réalisée avec la div instruction, le dividende est initialement la plus haute puissance de dix 16 bits d' ajustement (10 4) et il est réduit à des puissances inférieures à chaque itération.

Paramètres

Les paramètres sont affichés par ordre de poussée.
Chacun est de 16 bits.

Paramètre La description
nombre Le nombre non signé 16 bits à imprimer en décimal
afficher les zéros en tête Si 0 aucun zéros non significatif n'est imprimé, sinon ils le sont. Le nombre 0 est toujours imprimé comme "0"

Usage

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

Portage NASM

Pour porter le code sur NASM, supprimez le mot-clé PTR des accès mémoire (par exemple, mov ax, WORD PTR [bp+06h] devient mov ax, WORD [bp+06h] )



Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow