Buscar..


Observaciones

Convertir cadenas en números enteros es una de las tareas comunes.

Aquí mostraremos cómo convertir cadenas decimales en enteros.

El código de Psuedo para hacer esto es:

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

Tratar con cadenas hexadecimales es un poco más difícil porque los códigos de caracteres generalmente no son continuos cuando se trata de múltiples tipos de caracteres como dígitos (0-9) y alfabetos (af y AF). Los códigos de caracteres suelen ser continuos cuando se trata de un solo tipo de caracteres (trataremos con los dígitos aquí), por lo que trataremos solo con entornos en los que los códigos de caracteres para dígitos son continuos.

Asamblea IA-32, GAS, convención de 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

Este código de estilo GAS convertirá la cadena decimal dada como primer argumento, que se empuja en la pila antes de llamar a esta función, a entero y la devolverá a través de %eax . El valor de %esi se guarda porque es un registro de guardado de llamada y se utiliza.

Los caracteres de desbordamiento / ajuste y los caracteres no válidos no se verifican para simplificar el código.

En C, este código se puede usar de esta manera (suponiendo que el unsigned int y los punteros tengan una longitud de 4 bytes):

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

Nota: en algunos entornos, dos string_to_integer en el código de ensamblaje se deben cambiar a _string_to_integer (agregar guión bajo) para que funcione con el código C.

MS-DOS, función TASM / MASM para leer un entero sin signo de 16 bits

Lea un entero sin signo de 16 bits de la entrada.

Esta función utiliza el servicio de interrupción Int 21 / AH = 0Ah para leer una cadena con búfer.
El uso de una cadena de búfer permite al usuario revisar lo que ha escrito antes de pasarlo al programa para su procesamiento.
Se leen hasta seis dígitos (ya que 65535 = 2 16 - 1 tiene seis dígitos).

Además de realizar la conversión estándar de número a número, esta función también detecta entradas y desbordamientos no válidos (número demasiado grande para encajar en 16 bits).

Valores de retorno

La función devuelve el número leído en AX . Las banderas ZF , CF , OF indican si la operación se completó con éxito o no y por qué.

Error HACHA ZF CF DE
Ninguna El entero de 16 bits. Conjunto No establecido No establecido
Entrada inválida El número parcialmente convertido, hasta el último dígito válido encontrado No establecido Conjunto No establecido
Rebosar 7fffh No establecido Conjunto Conjunto

El ZF se puede usar para separar rápidamente entre entradas válidas y no válidas.

Uso

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

Código

;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

Portabilidad NASM

Para transferir el código a NASM, elimine la palabra clave PTR de los accesos a la memoria (por ejemplo, mov cl, BYTE PTR [si] convierte en mov cl, BYTE [si] )

MS-DOS, función TASM / MASM para imprimir un número de 16 bits en binario, cuaternario, octal y hexadecimal

Imprima un número en binario, cuaternario, octal, hexadecimal y una potencia general de dos

Todas las bases que son una potencia de dos, como las bases binaria (2 1 ), cuaternaria (2 2 ), octal (2 3 ), hexadecimal (2 4 ), tienen un número entero de bits por dígito 1 .
Por lo tanto, para recuperar cada dígito 2 de un número, simplemente dividimos el número de grupos de introducción de n bits a partir de la LSb (derecha).
Por ejemplo, para la base cuaternaria, dividimos un número de 16 bits en grupos de dos bits. Hay 8 de tales grupos.
No toda la potencia de dos bases tiene un número integral de grupos que se ajusta a 16 bits; por ejemplo, la base octal tiene 5 grupos de 3 bits que representan 3 · 5 = 15 bits de 16, dejando un grupo parcial de 1 bit 3 .

El algoritmo es simple, aislamos cada grupo con un cambio seguido de una operación AND .
Este procedimiento funciona para todos los tamaños de los grupos o, en otras palabras, para cualquier potencia base de dos.

Para mostrar los dígitos en el orden correcto, la función comienza al aislar el grupo más significativo (el que está más a la izquierda), por lo que es importante saber: a) cuántos bits D es un grupo y b) la posición del bit S donde está más a la izquierda comienza el grupo.
Estos valores están precomputados y almacenados en constantes cuidadosamente elaboradas.

Parámetros

Los parámetros deben ser empujados en la pila.
Cada uno es de 16 bits de ancho.
Se muestran en orden de empuje.

Parámetro Descripción
norte El número a convertir
Base La base a usar expresada usando las constantes BASE2 , BASE4 , BASE8 y BASE16
Imprimir ceros iniciales Si cero no se imprimen ceros no significativos, de lo contrario lo son. El número 0 se imprime como "0" aunque

Uso

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

Nota para los usuarios de TASM : si coloca las constantes definidas con EQU después del código que las utiliza, habilite el paso múltiple con la marca /m de TASM o obtendrá una anulación de las necesidades de Reenvío .

Código

;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

Datos

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

Portabilidad NASM

Para trasladar el código a NASM, elimine la palabra clave PTR de los accesos a la memoria (por ejemplo, mov si, WORD PTR [bp+08h] convierte en mov si, WORD PTR [bp+08h] )

Extendiendo la función

La función se puede extender fácilmente a cualquier base hasta 2 255 , aunque cada base por encima de 2 16 imprimirá el mismo número, ya que el número es solo de 16 bits.

Para añadir una base:

  1. Defina una nueva constante BASEx donde x es 2 n .
    El byte inferior, llamado D , es D = n .
    El byte superior, llamado S , es la posición, en bits, del grupo superior. Se puede calcular como S = n · (⌈16 / n ⌉ - 1).
  2. Agregue los dígitos necesarios a la cadena DIGITS .

Ejemplo: añadiendo base 32

Tenemos D = 5 y S = 15, por lo que definimos BASE32 EQU 0f05h .
Luego agregamos dieciséis dígitos más: DIGITS db "0123456789abcdefghijklmnopqrstuv" .

Como debe quedar claro, los dígitos se pueden cambiar editando la cadena DIGITS .


1 Si B es una base, entonces tiene B dígitos por definición. El número de bits por dígito es, por lo tanto, log 2 ( B ). Para la potencia de dos bases, esto se simplifica al registro 2 (2 n ) = n, que es un entero por definición.

2 En este contexto, se supone implícitamente que la base en consideración es una potencia de dos base 2 n .

3 Para que una base B = 2 n tenga un número entero de grupos de bits, debe ser que n | 16 ( n divide 16). Dado que el único factor en 16 es 2, debe ser que n sea ​​en sí mismo una potencia de dos. Entonces B tiene la forma 2 2 k o, de manera equivalente, log 2 ( log 2 ( B )) debe ser un número entero.

MS-DOS, TASM / MASM, función para imprimir un número de 16 bits en decimal

Imprima un número sin firmar de 16 bits en decimal

El servicio de interrupción Int 21 / AH = 02h se utiliza para imprimir los dígitos.
La conversión estándar de número a número se realiza con la instrucción div , el dividendo es inicialmente la potencia más alta de diez bits de 16 bits (10 4 ) y se reduce a potencias más bajas en cada iteración.

Parámetros

Los parámetros se muestran en orden de empuje.
Cada uno es de 16 bits.

Parámetro Descripción
número El número sin signo de 16 bits para imprimir en decimal
mostrar ceros iniciales Si 0 no se imprimen ceros no significativos, si no lo son. El número 0 siempre se imprime como "0"

Uso

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

Código

;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

Portabilidad NASM

Para transferir el código a NASM, elimine la palabra clave PTR de los accesos a la memoria (por ejemplo, mov ax, WORD PTR [bp+06h] convierte en mov ax, WORD [bp+06h] )



Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow