Intel x86 Assembly Language & Microarchitecture
10 진수 문자열을 정수로 변환
수색…
비고
문자열을 정수로 변환하는 것이 일반적인 작업 중 하나입니다.
여기에서는 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 , BASE8 및 BASE16 을 사용하여 표현할 사용 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 비트 인 것과 같은 숫자를 인쇄합니다.
기본을 추가하려면 :
- x 가 2 n 인 새로운 상수
BASEx정의하십시오.
D 라는 하위 바이트는 D = n 입니다.
상위 바이트 S 는 상위 그룹의 비트 단위 위치입니다. 그것은 S = n · (⌈16 / n ⌉-1)로 계산 될 수있다. - 필요한 숫자를
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] ).