수색…


비고

문자열을 정수로 변환하는 것이 일반적인 작업 중 하나입니다.

여기에서는 10 진수 문자열을 정수로 변환하는 방법을 보여줍니다.

이렇게하기위한 Psuedo 코드는 다음과 같습니다.

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

숫자 (0-9) 및 영문 (af 및 AF)과 같은 여러 문자 유형을 처리 할 때는 일반적으로 문자 코드가 연속적이지 않기 때문에 16 진수 문자열을 다루는 것이 조금 더 어렵습니다. 문자 코드는 일반적으로 하나의 문자 유형을 처리 할 때 연속적입니다 (여기서 숫자를 다룰 것입니다). 따라서 숫자에 대한 문자 코드가 연속적인 환경 만 처리 할 것입니다.

IA-32 어셈블리, GAS, 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

이 GAS 스타일의 코드는이 함수를 호출하기 전에 스택에 푸시 된 첫 번째 인수로 지정된 십진수 문자열을 정수로 변환하고 %eax 를 통해 반환합니다. %esi 의 값은 callee-save 레지스터이며 사용되므로 저장됩니다.

오버플로 / 줄 바꿈 및 유효하지 않은 문자는 코드를 단순하게 만들기 위해 검사되지 않습니다.

C에서는이 코드를 다음과 같이 사용할 수 있습니다 ( unsigned int 및 포인터는 4 바이트 길이라고 가정).

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

참고 : 일부 환경에서는 어셈블리 코드의 두 string_to_integer_string_to_integer (밑줄 추가)로 변경해야 C 코드와 함께 사용할 수 있습니다.

MS-DOS, 16 비트 부호없는 정수를 읽는 TASM / MASM 함수

입력에서 부호없는 16 비트 정수를 읽습니다.

이 함수는 버퍼링 된 문자열을 읽기 위해 인터럽트 서비스 Int 21 / AH = 0Ah 를 사용합니다.
버퍼링 된 문자열을 사용하면 입력 한 내용을 검토하여 처리를 위해 프로그램에 전달하기 전에 사용자가 검토 할 수 있습니다.
(1 - 6 자리 갖는다 65535 = 2 (16)로)을 최대 6 개 개의 숫자를 판독한다.

이 기능을 계수 함 부호로부터 표준 변환을 행하는 외에 무효 입력 및 플로우 (16 개 비트를 맞추기에는 너무 큰 수)를 검출한다.

반환 값

이 함수는 AX 에서 읽은 숫자를 반환합니다. 플래그 ZF , CF , OF 는 작업이 성공적으로 완료되었는지 여부와 그 이유를 알려줍니다.

오류 도끼 ZF CF
없음 16 비트 정수 세트 설정되지 않음 설정되지 않음
잘못된 입력 만난 마지막 유효 숫자까지 부분적으로 변환 된 숫자 설정되지 않음 세트 설정되지 않음
과다 7fffh 설정되지 않음 세트 세트

ZF 를 사용하면 유효하지 않은 입력과 유효하지 않은 입력을 신속하게 구분할 수 있습니다.

용법

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

암호

;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 포팅

코드를 NASM으로 이식하려면 메모리 액세스에서 PTR 키워드를 제거하십시오 (예 : mov cl, BYTE PTR [si]mov cl, BYTE [si] ).

MS-DOS, 이진, 4 진수, 8 진수, 16 진수로 16 비트 숫자를 인쇄하는 TASM / MASM 함수

2 진수, 4 진수, 8 진수, 16 진수 및 2의 일반 제곱수로 숫자 인쇄

바이너리 (2 1),(2) 진수 (3 : 2) 16 진수 (2-4)과 같은 염기 2의 제곱 모든 염기는 1 자리수 당 비트의 정수를 갖는다.
따라서 숫자의 각 자릿수 2 를 검색하려면 LSb (오른쪽)에서 시작하는 n 비트의 숫자 인트로 그룹을 간단히 나눕니다.
예를 들어 4 진베이스의 경우 2 비트 그룹으로 16 비트 숫자를 나눕니다. 그러한 그룹 중 8 개가 있습니다.
두베이스의 모든 힘이 16 비트에 맞는 정수를 가지고 있지는 않습니다. 예를 들어, 8 진베이스는 16 비트 중 3 비트 5 비트를 차지하는 3 비트의 5 개 그룹을 가지며 1 비트 3 의 부분 그룹을 남깁니다.

알고리즘은 간단합니다. 우리는 shift와 함께 각 그룹을 분리하고 AND 연산을 수행합니다.
이 절차는 그룹의 모든 크기에 대해 작동합니다. 즉, 기본 단위 인 2의 기본 단위에 적용됩니다.

최상위 그룹 (가장 왼쪽) 분리하여 적절한 순서로 기능 시작 숫자를 표시하기 위해, 이에 의해 아는 것이 중요하다 : a) 얼마나 많은 비트가 기이고 D 및 b) 상기 비트 위치 S 여기서 가장 왼쪽 그룹이 시작됩니다.
이 값은 사전 계산되어 신중하게 제작 된 상수에 저장됩니다.

매개 변수

매개 변수는 스택에 푸시되어야합니다.
각각은 16 비트 폭입니다.
그들은 밀기의 순서로 보여집니다.

매개 변수 기술
변환 할 숫자
베이스 상수 BASE2 , BASE4 , BASE8BASE16 을 사용하여 표현할 사용 BASE16
선행 제로 인쇄 0 이면 중요하지 않은 0은 인쇄되지 않으며, 그렇지 않은 경우 0입니다. 숫자 0은 "0"으로 인쇄됩니다.

용법

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

TASM 사용자 참고 사항 : 당신이 정의 된 상수 넣으면 EQU 를 사용하는 코드 후을의 멀티 패스 가능 /m TASM의 플래그를하거나 앞으로 참조 요구를 무시할 수 있습니다.

암호

;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

데이터

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 포팅

코드를 NASM으로 이식하려면 메모리 액세스에서 PTR 키워드를 제거하십시오 (예 : mov si, WORD PTR [bp+08h]mov si, WORD PTR [bp+08h] )

함수 확장하기

이 기능은 2에서 255 까지의 기본 단위로 쉽게 확장 할 수 있지만 2 16 보다 큰 기본 단위는 숫자가 16 비트 인 것과 같은 숫자를 인쇄합니다.

기본을 추가하려면 :

  1. x 가 2 n 인 새로운 상수 BASEx 정의하십시오.
    D 라는 하위 바이트는 D = n 입니다.
    상위 바이트 S 는 상위 그룹의 비트 단위 위치입니다. 그것은 S = n · (⌈16 / n ⌉-1)로 계산 될 수있다.
  2. 필요한 숫자를 DIGITS 문자열에 추가하십시오.

예 :베이스 추가 32

우리는 D = 5이고 S = 15이므로 BASE32 EQU 0f05h 정의합니다.
그런 다음 16 자리 숫자 더 추가합니다 : DIGITS db "0123456789abcdefghijklmnopqrstuv" .

명확해야하므로 DIGITS 문자열을 편집하여 숫자를 변경할 수 있습니다.


1 B 가 기본이면 정의 당 B 자릿수입니다. 따라서 1 비트 당 비트 수는 log 2 ( B )입니다. 2 개의베이스의 멱 (power)에 대해 이것은 정의에 의해 정수인 log 2 (2 n ) = n 을 단순화합니다.

2 이 문맥에서 고려중인 염기가 2 개의 밑수 2 n 의 힘이라는 것이 암묵적으로 가정된다.

3 베이스 B = 2 n 이 비트 그룹의 정수를 가지려면 n | 16 ( n은 16으로 나눕니다). 16의 유일한 요소는 2이므로 n 은 그 자체가 2의 거듭 제곱이어야합니다. 따라서 B 는 2 2 k 또는 동등하게 log 2 ( log 2 ( B ))의 형식을 가져야합니다.

MS-DOS, TASM / MASM, 10 진수로 16 비트 숫자를 출력하는 기능

10 진수로 16 비트 부호없는 숫자를 인쇄하십시오.

인터럽트 서비스 Int 21 / AH = 02h 는 숫자를 인쇄하는 데 사용됩니다.
번호에 다수의 표준 변환이 수행된다 div 지시 배당은 처음 16 비트 열 피팅 (104)의 가장 높은 힘과 각 반복에서 낮은 전력으로 감소된다.

매개 변수

매개 변수는 푸시 순서로 표시됩니다.
각각 16 비트입니다.

매개 변수 기술
번호 10 진수로 인쇄 할 16 비트 부호없는 숫자
맨 앞에 0을 표시합니다. 0의 경우, 의미가없는 0은 인쇄되지 않습니다. 그렇지 않은 경우는 0입니다. 숫자 0은 항상 "0"으로 인쇄됩니다.

용법

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

암호

;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 포팅

코드를 NASM으로 이식하려면 메모리 액세스에서 PTR 키워드를 제거하십시오 (예 : mov ax, WORD PTR [bp+06h]mov ax, WORD [bp+06h] ).



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow