将计算出字母表中两个字母的距离
will work out how far apart two letters are in the alphabet
然后程序会计算出两个字母的位置之间的差异
字母表,并将其显示到屏幕上。例如,“a”和“e”之间的差值是 4。
“d”和“b”之间的差异是 2。“c”和“c”之间的差异是 0。
这就是我所做的,但我不知道如何计算字母之间的差距
SECTION .bss
SECTION .data
tMsg: db "fist letter",10
tLen: equ $-tMsg
Input: times 100 db 0
ok: db "ok"
oklen: equ $-ok
yMsg: db "Second letter",10
yLen: equ $-yMsg
SECTION .text
global _start
_start:
nop
mov eax,4
mov ebx,1
mov ecx,tMsg
mov edx,tLen
int 80H
mov eax,3
mov ebx,0
mov ecx,Input
mov edx,100
int 80H
mov ax, [Input]
mov bx, [ok]
cmp ax, bx
je y
mov eax,1
mov ebx,0
int 80H
y:
mov eax,4
mov ebx,1
mov ecx,yMsg
mov edx,yLen
int 80H
mov eax,1
mov ebx,0
int 80H
如果您仍然卡住,您的问题要求您确定两个字符之间的距离。这带来了许多您必须实施的检查。尽管您的问题对是否需要同时处理大写和小写字母距离保持沉默,但除非您将所有内容都转换为一种情况或另一种情况,否则您将需要确定两个字符是否具有相同的大小写以使字母表之间的距离这两个字符有效。
由于涉及到两个字符,你需要一种方法来保存第一个字符的大小写,以便与第二个字符的大小写进行比较。在这里,在所有需要简单状态的情况下,只使用一个字节(标志)来存储状态就和其他任何东西一样简单。例如,如果 ASCII 字符不是字母字符,则保存 0
的字节,如果字符是大写字符,则保存 1
,如果字符是小写字符,则保存 2
(或您喜欢的任何一致方案) )
这样,当您完成比较和测试后,您可以简单地比较两个标志是否相等。如果它们相等,您可以继续从另一个中减去一个以获得距离(如果需要交换),然后输出将数字转换为 ASCII 数字输出的数字。
判断字符是否为大写字符,类似于C中的isupper()
,只需要一个简短的函数:
; check if character isupper()
; parameters:
; ecx - address holding character
; returns;
; eax - 0 (false), 1 (true)
_isupr:
mov eax, 1 ; set return true
cmp byte[ecx], 'A' ; compare with 'A'
jge _chkZ ; char >= 'A'
mov eax, 0 ; set return false
ret
_chkZ:
cmp byte[ecx], 'Z' ; compare with 'Z'
jle _rtnupr ; <= is uppercase
mov eax, 0 ; set return false
_rtnupr:
ret
您可以通过多种方式处理您需要的本地数组和值的存储。您可以从当前堆栈指针中减去以在堆栈上创建临时存储,或者以更易读的方式创建标签以存储在未初始化的段 (.bss) 中并将标签用作变量名。您初始化的变量进入 .data 段。例如,程序的存储可以是:
section .bss
buf resb 32 ; general buffer, used by _prnuint32
bufa resb 8 ; storage for first letter line
bufb resb 8 ; storage for second letter line
lena resb 4 ; length of first letter line
lenb resb 4 ; length of second letter line
nch resb 1 ; number of digit characters in _prnuint32
ais resb 1 ; what 1st char is, 0-notalpha, 1-upper, 2-lower
bis resb 1 ; same for 2nd char
与其使用散布在系统调用设置中的数字,不如声明初始化标签,例如stdin
和 stdout
而不是使用 0
和 1
使事情更具可读性:
section .data
bufsz: equ 32
babsz: equ 8
tmsg: db "first letter : "
tlen: equ $-tmsg
ymsg: db "second letter: "
ylen: equ $-ymsg
dmsg: db "char distance: "
dlen: equ $-dmsg
emsg: db "error: not alpha or same case", 0xa
elen: equ $-emsg
nl: db 0xa
stdin: equ 0
stdout: equ 1
read: equ 3
write: equ 4
exit: equ 1
然后为了读取您的字符输入,您将有,例如
mov eax, write ; prompt for 1st letter
mov ebx, stdout
mov ecx, tmsg
mov edx, tlen
int 80h ; __NR_write
mov eax, read ; read 1st letter line
mov ebx, stdin
mov ecx, bufa
mov edx, babsz
int 80h ; __NR_read
mov [lena], eax ; save no. of character in line
然后检查字符输入的大小写,你可以这样做:
call _isupr ; check if uppercase
cmp eax, 1 ; check return 0-false, 1-true
jne chkalwr ; if not, branch to check lowercase
mov byte[ais], 1 ; set uppercase flag for 1st letter
jmp getb ; branch to get 2nd letter
chkalwr:
call _islwr ; check if lowercase
cmp eax, 1 ; check return
jne notalpha ; 1st letter not alpha char, display error
mov byte[ais], 2 ; set lowercase flag for 1st char
notalpha:
标签只是一个块,用于在字符不是字母字符或两个字符之间的大小写不匹配时输出错误:
notalpha: ; show not alpha or not same case error
mov eax, write
mov ebx, stdout
mov ecx, emsg
mov edx, elen
int 80h ; __NR_write
mov ebx, 1 ; set EXIT_FAILURE
完成两个字符的输入和分类后,现在需要验证两个字符是否大小写相同,如果是则需要计算字符之间的距离(必要时交换,或使用绝对值) value) 最后处理它们之间的距离从数值到 ASCII 数字的转换输出。您可以执行类似以下操作:
chkboth:
mov al, byte[ais] ; load flags into al, bl
mov bl, byte[bis]
cmp al, bl ; compare flags equal, else not same case
jne notalpha
mov eax, write ; display distance output
mov ebx, stdout
mov ecx, dmsg
mov edx, dlen
int 80h ; __NR_write
mov al, byte[bufa] ; load chars into al, bl
mov bl, byte[bufb]
cmp al, bl ; chars equal, zero difference
jns getdiff ; 1st char >= 2nd char
push eax ; swap chars
push ebx
pop eax
pop ebx
getdiff:
sub eax, ebx ; subtract 2nd char from 1st char
call _prnuint32 ; output difference
xor ebx, ebx ; set EXIT_SUCCESS
jmp done
把它放在一起,包括下面的_prnuint32
函数,用于转换和输出字符之间的数字距离,你会得到:
section .bss
buf resb 32 ; general buffer, used by _prnuint32
bufa resb 8 ; storage for first letter line
bufb resb 8 ; storage for second letter line
lena resb 4 ; length of first letter line
lenb resb 4 ; length of second letter line
nch resb 1 ; number of digit characters in _prnuint32
ais resb 1 ; what 1st char is, 0-notalpha, 1-upper, 2-lower
bis resb 1 ; same for 2nd char
section .data
bufsz: equ 32
babsz: equ 8
tmsg: db "first letter : "
tlen: equ $-tmsg
ymsg: db "second letter: "
ylen: equ $-ymsg
dmsg: db "char distance: "
dlen: equ $-dmsg
emsg: db "error: not alpha or same case", 0xa
elen: equ $-emsg
nl: db 0xa
stdin: equ 0
stdout: equ 1
read: equ 3
write: equ 4
exit: equ 1
section .text
global _start:
_start:
mov byte[ais], 0 ; zero flags
mov byte[bis], 0
mov eax, write ; prompt for 1st letter
mov ebx, stdout
mov ecx, tmsg
mov edx, tlen
int 80h ; __NR_write
mov eax, read ; read 1st letter line
mov ebx, stdin
mov ecx, bufa
mov edx, babsz
int 80h ; __NR_read
mov [lena], eax ; save no. of character in line
call _isupr ; check if uppercase
cmp eax, 1 ; check return 0-false, 1-true
jne chkalwr ; if not, branch to check lowercase
mov byte[ais], 1 ; set uppercase flag for 1st letter
jmp getb ; branch to get 2nd letter
chkalwr:
call _islwr ; check if lowercase
cmp eax, 1 ; check return
jne notalpha ; 1st letter not alpha char, display error
mov byte[ais], 2 ; set lowercase flag for 1st char
getb:
mov eax, write ; prompt for 2nd letter
mov ebx, stdout
mov ecx, ymsg
mov edx, ylen
int 80h ; __NR_write
mov eax, read ; read 2nd letter line
mov ebx, stdin
mov ecx, bufb
mov edx, babsz
int 80h ; __NR_read
mov [lenb], eax ; save no. of character in line
call _isupr ; same checks for 2nd character
cmp eax, 1
jne chkblwr
mov byte[bis], 1
jmp chkboth
chkblwr:
call _islwr
cmp eax, 1
jne notalpha
mov byte[bis], 2
chkboth:
mov al, byte[ais] ; load flags into al, bl
mov bl, byte[bis]
cmp al, bl ; compare flags equal, else not same case
jne notalpha
mov eax, write ; display distance output
mov ebx, stdout
mov ecx, dmsg
mov edx, dlen
int 80h ; __NR_write
mov al, byte[bufa] ; load chars into al, bl
mov bl, byte[bufb]
cmp al, bl ; chars equal, zero difference
jns getdiff ; 1st char >= 2nd char
push eax ; swap chars
push ebx
pop eax
pop ebx
getdiff:
sub eax, ebx ; subtract 2nd char from 1st char
call _prnuint32 ; output difference
xor ebx, ebx ; set EXIT_SUCCESS
jmp done
notalpha: ; show not alpha or not same case error
mov eax, write
mov ebx, stdout
mov ecx, emsg
mov edx, elen
int 80h ; __NR_write
mov ebx, 1 ; set EXIT_FAILURE
done:
mov eax, exit ; __NR_exit
int 80h
; print unsigned 32-bit number to stdout
; arguments:
; eax - number to output
; returns:
; none
_prnuint32:
mov byte[nch], 0 ; zero nch counter
mov ecx, 0xa ; base 10 (and newline)
lea esi, [buf + 31] ; load address of last char in buf
mov [esi], cl ; put newline in buf
inc byte[nch] ; increment char count in buf
_todigit: ; do {
xor edx, edx ; zero remainder register
div ecx ; edx=remainder = low digit = 0..9. eax/=10
or edx, '0' ; convert to ASCII
dec esi ; backup to next char in buf
mov [esi], dl ; copy ASCII digit to buf
inc byte[nch] ; increment char count in buf
test eax, eax ; } while (eax);
jnz _todigit
mov eax, 4 ; __NR_write from /usr/include/asm/unistd_32.h
mov ebx, 1 ; fd = STDOUT_FILENO
mov ecx, esi ; copy address in esi to ecx (addr of 1st digit)
; subtracting to find length.
mov dl, byte[nch] ; length, including the \n
int 80h ; write(1, string, digits + 1)
ret
; check if character islower()
; parameters:
; ecx - address holding character
; returns;
; eax - 0 (false), 1 (true)
_islwr:
mov eax, 1 ; set return true
cmp byte[ecx], 'a' ; compare with 'a'
jge _chkz ; char >= 'a'
mov eax, 0 ; set return false
ret
_chkz:
cmp byte[ecx], 'z' ; compare with 'z'
jle _rtnlwr ; <= is lowercase
mov eax, 0 ; set return false
_rtnlwr:
ret
; check if character isupper()
; parameters:
; ecx - address holding character
; returns;
; eax - 0 (false), 1 (true)
_isupr:
mov eax, 1 ; set return true
cmp byte[ecx], 'A' ; compare with 'A'
jge _chkZ ; char >= 'A'
mov eax, 0 ; set return false
ret
_chkZ:
cmp byte[ecx], 'Z' ; compare with 'Z'
jle _rtnupr ; <= is uppercase
mov eax, 0 ; set return false
_rtnupr:
ret
有很多方法可以编写不同的片段,与最有效的编写方式相比,这里更容易理解。
例子Use/Output
编译后link代码,例如
nasm -f elf -o ./obj/char_dist_32.o char_dist_32.asm
ld -m elf_i386 -o ./bin/char_dist_32 ./obj/char_dist_32.o
您可以使用您的问题和其他问题中给出的输入进行测试,例如
$ ./bin/char_dist_32
first letter : a
second letter: e
char distance: 4
$ ./bin/char_dist_32
first letter : d
second letter: b
char distance: 2
$ ./bin/char_dist_32
first letter : D
second letter: B
char distance: 2
$ ./bin/char_dist_32
first letter : a
second letter: Z
error: not alpha or same case
检查一下,如果您还有其他问题,请告诉我。
就像abs(c1 - c2)
一样简单。您可以减去 ASCII 码; +'a'
部分将抵消。
或者,如果您想要不区分大小写,请使用 c1|=0x20
强制字符先小写。请参阅 What is the idea behind ^= 32, that converts lowercase letters to upper and vice versa?(它还提供了一种有效的方法来 检查 如果输入是字母的并转换为小写字母,从而导致字母表中的 0..25 位置)。
一般情况下,How do I print an integer in Assembly Level Programming without printf from the c library? 涵盖了将数字打印为十进制 ASCII 数字串。如果我们可以假设一个 2 位数,我们可以简化,如果我们不介意打印前导零,则更是如此。
只是为了好玩,让我们看看我们可以把它做的多么简单。好吧,也许并不总是“简单”,而是紧凑和极简主义。需要理解的代码较少,但有些步骤并不是我希望初学者采用的方式。 (例如,同一寄存器不同位置的 2 个字符,并使用 8 位 DIV 的 AH:AL 结果作为字符串。)
对于初学者,我们将把两个字符放在同一行作为同一个 read
系统调用的一部分。 (命令行参数也很简单,但如果不检查 argc 会更简单,如果不提供它们就会崩溃。)
我省略了打印提示,因为那很无聊,如果你愿意,可以这样做。
SYS__exit equ 1
SYS_read equ 3
SYS_write equ 4
section .text ; optional, already the default section
global _start
_start:
sub esp, 32 ; reserve some stack space. I only ended up using 4 bytes
mov eax, SYS_read
xor ebx, ebx ; ebx=0 = stdin
mov ecx, esp
mov edx, 4 ; long enough to get 2 chars and a newline with room to spare
int 0x80 ; read(STDIN_FILENO, stackbuf, 4)
movzx eax, word [ecx] ; load both chars into AL and AH
or eax, 0x2020 ; force them both to lower case, operating on AL and AH at once
;;; if you want to check for non-alphabetic chars, add code here
sub al, ah ; subtract ASCII codes
jns .done_abs ; jump if result wasn't negative
neg al ; AL = abx(al)
.done_abs:
movzx eax, al ; clear AH
mov dl, 10
div dl ; AL = diff/10 (leading digit) AH = diff%10 (least significant digit)
add eax, `00\n` ; 0..9 integer digits to ASCII codes and append a newline
mov [ecx], eax ; store ASCII chars back into the same stack buffer
mov eax, SYS_write
mov ebx, 1 ; stdout
;mov ecx, esp ; still set
mov edx, 3 ; 2-digit number + newline, maybe including leading zero
int 0x80 ; write(1, stackbuf, 3)
mov eax, SYS__exit
xor ebx, ebx
int 0x80 ; _exit(0)
有趣的事实:尽管使用了部分寄存器,这主要避免了部分寄存器停顿。 (除了在 div dl
写入 AX 之后添加到 EAX。)如果您实际上是在优化性能,您将使用乘法逆。 (https://codereview.stackexchange.com/questions/142842/integer-to-ascii-algorithm-x86-assembly)
测试用例:
$ nasm -felf32 -Worphan-labels char-diff.asm &&
ld -melf_i386 -o char-diff char-diff.o
$ ./char-diff
ab
01
$ ./char-diff
Ax
23
$ ./char-diff
Aa
00
$ ./char-diff
Xa
23
$ ./char-diff
xA
23
然后程序会计算出两个字母的位置之间的差异 字母表,并将其显示到屏幕上。例如,“a”和“e”之间的差值是 4。 “d”和“b”之间的差异是 2。“c”和“c”之间的差异是 0。 这就是我所做的,但我不知道如何计算字母之间的差距
SECTION .bss
SECTION .data
tMsg: db "fist letter",10
tLen: equ $-tMsg
Input: times 100 db 0
ok: db "ok"
oklen: equ $-ok
yMsg: db "Second letter",10
yLen: equ $-yMsg
SECTION .text
global _start
_start:
nop
mov eax,4
mov ebx,1
mov ecx,tMsg
mov edx,tLen
int 80H
mov eax,3
mov ebx,0
mov ecx,Input
mov edx,100
int 80H
mov ax, [Input]
mov bx, [ok]
cmp ax, bx
je y
mov eax,1
mov ebx,0
int 80H
y:
mov eax,4
mov ebx,1
mov ecx,yMsg
mov edx,yLen
int 80H
mov eax,1
mov ebx,0
int 80H
如果您仍然卡住,您的问题要求您确定两个字符之间的距离。这带来了许多您必须实施的检查。尽管您的问题对是否需要同时处理大写和小写字母距离保持沉默,但除非您将所有内容都转换为一种情况或另一种情况,否则您将需要确定两个字符是否具有相同的大小写以使字母表之间的距离这两个字符有效。
由于涉及到两个字符,你需要一种方法来保存第一个字符的大小写,以便与第二个字符的大小写进行比较。在这里,在所有需要简单状态的情况下,只使用一个字节(标志)来存储状态就和其他任何东西一样简单。例如,如果 ASCII 字符不是字母字符,则保存 0
的字节,如果字符是大写字符,则保存 1
,如果字符是小写字符,则保存 2
(或您喜欢的任何一致方案) )
这样,当您完成比较和测试后,您可以简单地比较两个标志是否相等。如果它们相等,您可以继续从另一个中减去一个以获得距离(如果需要交换),然后输出将数字转换为 ASCII 数字输出的数字。
判断字符是否为大写字符,类似于C中的isupper()
,只需要一个简短的函数:
; check if character isupper()
; parameters:
; ecx - address holding character
; returns;
; eax - 0 (false), 1 (true)
_isupr:
mov eax, 1 ; set return true
cmp byte[ecx], 'A' ; compare with 'A'
jge _chkZ ; char >= 'A'
mov eax, 0 ; set return false
ret
_chkZ:
cmp byte[ecx], 'Z' ; compare with 'Z'
jle _rtnupr ; <= is uppercase
mov eax, 0 ; set return false
_rtnupr:
ret
您可以通过多种方式处理您需要的本地数组和值的存储。您可以从当前堆栈指针中减去以在堆栈上创建临时存储,或者以更易读的方式创建标签以存储在未初始化的段 (.bss) 中并将标签用作变量名。您初始化的变量进入 .data 段。例如,程序的存储可以是:
section .bss
buf resb 32 ; general buffer, used by _prnuint32
bufa resb 8 ; storage for first letter line
bufb resb 8 ; storage for second letter line
lena resb 4 ; length of first letter line
lenb resb 4 ; length of second letter line
nch resb 1 ; number of digit characters in _prnuint32
ais resb 1 ; what 1st char is, 0-notalpha, 1-upper, 2-lower
bis resb 1 ; same for 2nd char
与其使用散布在系统调用设置中的数字,不如声明初始化标签,例如stdin
和 stdout
而不是使用 0
和 1
使事情更具可读性:
section .data
bufsz: equ 32
babsz: equ 8
tmsg: db "first letter : "
tlen: equ $-tmsg
ymsg: db "second letter: "
ylen: equ $-ymsg
dmsg: db "char distance: "
dlen: equ $-dmsg
emsg: db "error: not alpha or same case", 0xa
elen: equ $-emsg
nl: db 0xa
stdin: equ 0
stdout: equ 1
read: equ 3
write: equ 4
exit: equ 1
然后为了读取您的字符输入,您将有,例如
mov eax, write ; prompt for 1st letter
mov ebx, stdout
mov ecx, tmsg
mov edx, tlen
int 80h ; __NR_write
mov eax, read ; read 1st letter line
mov ebx, stdin
mov ecx, bufa
mov edx, babsz
int 80h ; __NR_read
mov [lena], eax ; save no. of character in line
然后检查字符输入的大小写,你可以这样做:
call _isupr ; check if uppercase
cmp eax, 1 ; check return 0-false, 1-true
jne chkalwr ; if not, branch to check lowercase
mov byte[ais], 1 ; set uppercase flag for 1st letter
jmp getb ; branch to get 2nd letter
chkalwr:
call _islwr ; check if lowercase
cmp eax, 1 ; check return
jne notalpha ; 1st letter not alpha char, display error
mov byte[ais], 2 ; set lowercase flag for 1st char
notalpha:
标签只是一个块,用于在字符不是字母字符或两个字符之间的大小写不匹配时输出错误:
notalpha: ; show not alpha or not same case error
mov eax, write
mov ebx, stdout
mov ecx, emsg
mov edx, elen
int 80h ; __NR_write
mov ebx, 1 ; set EXIT_FAILURE
完成两个字符的输入和分类后,现在需要验证两个字符是否大小写相同,如果是则需要计算字符之间的距离(必要时交换,或使用绝对值) value) 最后处理它们之间的距离从数值到 ASCII 数字的转换输出。您可以执行类似以下操作:
chkboth:
mov al, byte[ais] ; load flags into al, bl
mov bl, byte[bis]
cmp al, bl ; compare flags equal, else not same case
jne notalpha
mov eax, write ; display distance output
mov ebx, stdout
mov ecx, dmsg
mov edx, dlen
int 80h ; __NR_write
mov al, byte[bufa] ; load chars into al, bl
mov bl, byte[bufb]
cmp al, bl ; chars equal, zero difference
jns getdiff ; 1st char >= 2nd char
push eax ; swap chars
push ebx
pop eax
pop ebx
getdiff:
sub eax, ebx ; subtract 2nd char from 1st char
call _prnuint32 ; output difference
xor ebx, ebx ; set EXIT_SUCCESS
jmp done
把它放在一起,包括下面的_prnuint32
函数,用于转换和输出字符之间的数字距离,你会得到:
section .bss
buf resb 32 ; general buffer, used by _prnuint32
bufa resb 8 ; storage for first letter line
bufb resb 8 ; storage for second letter line
lena resb 4 ; length of first letter line
lenb resb 4 ; length of second letter line
nch resb 1 ; number of digit characters in _prnuint32
ais resb 1 ; what 1st char is, 0-notalpha, 1-upper, 2-lower
bis resb 1 ; same for 2nd char
section .data
bufsz: equ 32
babsz: equ 8
tmsg: db "first letter : "
tlen: equ $-tmsg
ymsg: db "second letter: "
ylen: equ $-ymsg
dmsg: db "char distance: "
dlen: equ $-dmsg
emsg: db "error: not alpha or same case", 0xa
elen: equ $-emsg
nl: db 0xa
stdin: equ 0
stdout: equ 1
read: equ 3
write: equ 4
exit: equ 1
section .text
global _start:
_start:
mov byte[ais], 0 ; zero flags
mov byte[bis], 0
mov eax, write ; prompt for 1st letter
mov ebx, stdout
mov ecx, tmsg
mov edx, tlen
int 80h ; __NR_write
mov eax, read ; read 1st letter line
mov ebx, stdin
mov ecx, bufa
mov edx, babsz
int 80h ; __NR_read
mov [lena], eax ; save no. of character in line
call _isupr ; check if uppercase
cmp eax, 1 ; check return 0-false, 1-true
jne chkalwr ; if not, branch to check lowercase
mov byte[ais], 1 ; set uppercase flag for 1st letter
jmp getb ; branch to get 2nd letter
chkalwr:
call _islwr ; check if lowercase
cmp eax, 1 ; check return
jne notalpha ; 1st letter not alpha char, display error
mov byte[ais], 2 ; set lowercase flag for 1st char
getb:
mov eax, write ; prompt for 2nd letter
mov ebx, stdout
mov ecx, ymsg
mov edx, ylen
int 80h ; __NR_write
mov eax, read ; read 2nd letter line
mov ebx, stdin
mov ecx, bufb
mov edx, babsz
int 80h ; __NR_read
mov [lenb], eax ; save no. of character in line
call _isupr ; same checks for 2nd character
cmp eax, 1
jne chkblwr
mov byte[bis], 1
jmp chkboth
chkblwr:
call _islwr
cmp eax, 1
jne notalpha
mov byte[bis], 2
chkboth:
mov al, byte[ais] ; load flags into al, bl
mov bl, byte[bis]
cmp al, bl ; compare flags equal, else not same case
jne notalpha
mov eax, write ; display distance output
mov ebx, stdout
mov ecx, dmsg
mov edx, dlen
int 80h ; __NR_write
mov al, byte[bufa] ; load chars into al, bl
mov bl, byte[bufb]
cmp al, bl ; chars equal, zero difference
jns getdiff ; 1st char >= 2nd char
push eax ; swap chars
push ebx
pop eax
pop ebx
getdiff:
sub eax, ebx ; subtract 2nd char from 1st char
call _prnuint32 ; output difference
xor ebx, ebx ; set EXIT_SUCCESS
jmp done
notalpha: ; show not alpha or not same case error
mov eax, write
mov ebx, stdout
mov ecx, emsg
mov edx, elen
int 80h ; __NR_write
mov ebx, 1 ; set EXIT_FAILURE
done:
mov eax, exit ; __NR_exit
int 80h
; print unsigned 32-bit number to stdout
; arguments:
; eax - number to output
; returns:
; none
_prnuint32:
mov byte[nch], 0 ; zero nch counter
mov ecx, 0xa ; base 10 (and newline)
lea esi, [buf + 31] ; load address of last char in buf
mov [esi], cl ; put newline in buf
inc byte[nch] ; increment char count in buf
_todigit: ; do {
xor edx, edx ; zero remainder register
div ecx ; edx=remainder = low digit = 0..9. eax/=10
or edx, '0' ; convert to ASCII
dec esi ; backup to next char in buf
mov [esi], dl ; copy ASCII digit to buf
inc byte[nch] ; increment char count in buf
test eax, eax ; } while (eax);
jnz _todigit
mov eax, 4 ; __NR_write from /usr/include/asm/unistd_32.h
mov ebx, 1 ; fd = STDOUT_FILENO
mov ecx, esi ; copy address in esi to ecx (addr of 1st digit)
; subtracting to find length.
mov dl, byte[nch] ; length, including the \n
int 80h ; write(1, string, digits + 1)
ret
; check if character islower()
; parameters:
; ecx - address holding character
; returns;
; eax - 0 (false), 1 (true)
_islwr:
mov eax, 1 ; set return true
cmp byte[ecx], 'a' ; compare with 'a'
jge _chkz ; char >= 'a'
mov eax, 0 ; set return false
ret
_chkz:
cmp byte[ecx], 'z' ; compare with 'z'
jle _rtnlwr ; <= is lowercase
mov eax, 0 ; set return false
_rtnlwr:
ret
; check if character isupper()
; parameters:
; ecx - address holding character
; returns;
; eax - 0 (false), 1 (true)
_isupr:
mov eax, 1 ; set return true
cmp byte[ecx], 'A' ; compare with 'A'
jge _chkZ ; char >= 'A'
mov eax, 0 ; set return false
ret
_chkZ:
cmp byte[ecx], 'Z' ; compare with 'Z'
jle _rtnupr ; <= is uppercase
mov eax, 0 ; set return false
_rtnupr:
ret
有很多方法可以编写不同的片段,与最有效的编写方式相比,这里更容易理解。
例子Use/Output
编译后link代码,例如
nasm -f elf -o ./obj/char_dist_32.o char_dist_32.asm
ld -m elf_i386 -o ./bin/char_dist_32 ./obj/char_dist_32.o
您可以使用您的问题和其他问题中给出的输入进行测试,例如
$ ./bin/char_dist_32
first letter : a
second letter: e
char distance: 4
$ ./bin/char_dist_32
first letter : d
second letter: b
char distance: 2
$ ./bin/char_dist_32
first letter : D
second letter: B
char distance: 2
$ ./bin/char_dist_32
first letter : a
second letter: Z
error: not alpha or same case
检查一下,如果您还有其他问题,请告诉我。
就像abs(c1 - c2)
一样简单。您可以减去 ASCII 码; +'a'
部分将抵消。
或者,如果您想要不区分大小写,请使用 c1|=0x20
强制字符先小写。请参阅 What is the idea behind ^= 32, that converts lowercase letters to upper and vice versa?(它还提供了一种有效的方法来 检查 如果输入是字母的并转换为小写字母,从而导致字母表中的 0..25 位置)。
一般情况下,How do I print an integer in Assembly Level Programming without printf from the c library? 涵盖了将数字打印为十进制 ASCII 数字串。如果我们可以假设一个 2 位数,我们可以简化,如果我们不介意打印前导零,则更是如此。
只是为了好玩,让我们看看我们可以把它做的多么简单。好吧,也许并不总是“简单”,而是紧凑和极简主义。需要理解的代码较少,但有些步骤并不是我希望初学者采用的方式。 (例如,同一寄存器不同位置的 2 个字符,并使用 8 位 DIV 的 AH:AL 结果作为字符串。)
对于初学者,我们将把两个字符放在同一行作为同一个 read
系统调用的一部分。 (命令行参数也很简单,但如果不检查 argc 会更简单,如果不提供它们就会崩溃。)
我省略了打印提示,因为那很无聊,如果你愿意,可以这样做。
SYS__exit equ 1
SYS_read equ 3
SYS_write equ 4
section .text ; optional, already the default section
global _start
_start:
sub esp, 32 ; reserve some stack space. I only ended up using 4 bytes
mov eax, SYS_read
xor ebx, ebx ; ebx=0 = stdin
mov ecx, esp
mov edx, 4 ; long enough to get 2 chars and a newline with room to spare
int 0x80 ; read(STDIN_FILENO, stackbuf, 4)
movzx eax, word [ecx] ; load both chars into AL and AH
or eax, 0x2020 ; force them both to lower case, operating on AL and AH at once
;;; if you want to check for non-alphabetic chars, add code here
sub al, ah ; subtract ASCII codes
jns .done_abs ; jump if result wasn't negative
neg al ; AL = abx(al)
.done_abs:
movzx eax, al ; clear AH
mov dl, 10
div dl ; AL = diff/10 (leading digit) AH = diff%10 (least significant digit)
add eax, `00\n` ; 0..9 integer digits to ASCII codes and append a newline
mov [ecx], eax ; store ASCII chars back into the same stack buffer
mov eax, SYS_write
mov ebx, 1 ; stdout
;mov ecx, esp ; still set
mov edx, 3 ; 2-digit number + newline, maybe including leading zero
int 0x80 ; write(1, stackbuf, 3)
mov eax, SYS__exit
xor ebx, ebx
int 0x80 ; _exit(0)
有趣的事实:尽管使用了部分寄存器,这主要避免了部分寄存器停顿。 (除了在 div dl
写入 AX 之后添加到 EAX。)如果您实际上是在优化性能,您将使用乘法逆。 (https://codereview.stackexchange.com/questions/142842/integer-to-ascii-algorithm-x86-assembly)
测试用例:
$ nasm -felf32 -Worphan-labels char-diff.asm &&
ld -melf_i386 -o char-diff char-diff.o
$ ./char-diff
ab
01
$ ./char-diff
Ax
23
$ ./char-diff
Aa
00
$ ./char-diff
Xa
23
$ ./char-diff
xA
23