Linux 部件中的查找编号为偶数/奇数
我试图找出一个给定的数字(由用户输入)是偶数还是奇数 我只是对编号的二进制数字应用Linux 部件中的查找编号为偶数/奇数,linux,assembly,x86,nasm,Linux,Assembly,X86,Nasm,我试图找出一个给定的数字(由用户输入)是偶数还是奇数 我只是对编号的二进制数字应用和运算。对于1,如果数字是奇数,则运算结果将是0,我们将输出奇数,否则我们将输出偶数 虽然逻辑看起来很简单,但在下面的代码中它不起作用。我不明白代码中的问题在哪里。谁能告诉我哪里出了问题 section .data userMsg db 'Please enter a number' lenuserMsg equ $ - userMsg even_msg db 'Even Number!
和
运算。对于1
,如果数字是奇数,则运算结果将是0
,我们将输出奇数,否则我们将输出偶数
虽然逻辑看起来很简单,但在下面的代码中它不起作用。我不明白代码中的问题在哪里。谁能告诉我哪里出了问题
section .data
userMsg db 'Please enter a number'
lenuserMsg equ $ - userMsg
even_msg db 'Even Number!'
len1 equ $ - even_msg
odd_msg db 'Odd Number!'
len2 equ $ - odd_msg
section .bss
num resb 5 ;Reserved 5 Bytes for Input
section .text
global _start ;must be declared for linker (gcc)
_start:
;User Prompt
mov ebx, 1 ;file descriptor (stdout)
mov ecx, userMsg ;message to write 'Please enter a number'
mov edx, lenuserMsg ;message length
mov eax, 4 ;system call number (sys_write)
int 0x80 ;call kernel
;Taking user input
mov ebx, 0 ;(stdin)
mov ecx, num
mov edx, 5 ;i/p length
mov eax, 3 ;system call number (sys_read)
int 0x80 ;call kernel
mov ax, [num]
and ax, 1
jz evnn ;Jump on Even
;Printing No. is Odd
mov ebx, 1 ;file descriptor (stdout)
mov ecx, odd_msg ;message to write 'Odd Number!'
mov edx, len2 ;message length
mov eax, 4 ;system call number (sys_write)
int 0x80 ;call kernel
jmp outprog ;Jump to exit
;Printing No. is Even
evnn:
mov ebx, 1 ;file descriptor (stdout)
mov ecx, even_msg ;message to write 'Even Number!'
mov edx, len1 ;message length
mov eax, 4 ;system call number (sys_write)
int 0x80 ;call kernel
;Exit
outprog:
mov eax, 1 ;system call number (sys_exit)
int 0x80 ;call kernel
您的代码不起作用,因为当您要求用户输入数字时,您读取的是ASCII编码的字符串。您需要先调用
atoi
(ASCII到INT)将字符串转换为计算机看到的“实数”<代码>atoi包含在glibc中
extern atoi
push eax ; pointer to your string to be converted, eg '123'
call atoi
; now eax contains your number, 123
您还可以对最低有效位(位0)进行位测试,以确定它是偶数还是奇数:
mov al, 01000_1101b
bt al, 0 ; copies the bit to the Carry Flag
jc its_odd ; jump if CF==1
; else - it's even (CF==0)
BT所做的是,它将位复制到CF,您可以在此基础上进行条件跳转。mov ax,[num]加载用户输入字符串的前两位,您正在测试第一位所以您实际上是在测试第一个字符的ASCII码是否为偶数 2是10的系数,因此只需测试最后一个十进制数字的低位,即可确定以10为基数的数字是偶数还是奇数 由于
'0'
的ASCII码是0x30,您可以只测试字符串最后一个ASCII字符的低位
您不需要调用atoi()
,除非您需要测试n%3
或其他不是10的系数的模数。(即,只需查看最后一位数字即可测试n%2
、n%5
、和n%10
)。请注意,您不能只测试低位十进制数字的低位2位来检查4的倍数,因为10不是4的倍数。e、 g.100%4=0
,但30%4=2
因此,给定一个指针+长度,您可以使用
测试字节[last_char],1
/jnzodd
。e、 g.输入后,在ECX中有一个指向字符串的指针,在EAX中有一个返回值(字节计数)
然后是奇数/偶数的实际测试:最后一个ASCII数字上只有一个测试和分支:
; We still have num in ECX, because int 0x80 doesn't clobber any regs (except for eax with the return value).
test byte [ecx + eax - 1], 1
jnz odd
把注意力集中在手头的真正问题上,好吗?如果说一个ASCII字符放在AL寄存器中,只需将它转换成一个数字,其余的就应该是自然的。在计算(二进制数和系统)中,整数的奇数或均匀度由位0决定。如果是1,则为奇数。如果为0,则为偶数。(我感到惊讶的是,到目前为止,还没有人特别强调这一点)
只是一个想法——(我已经30多年没有编写asm了),但是你确定输入num被视为一个数字吗?e、 g.我输入字母“a”时得到奇数,即ascii 65。是的,测试数字的低位是正确的,因为它们存储在base2中。如果奇偶分支只设置指针和长度,而不复制
int0x80
系统调用的其余部分,那么程序可能会更紧凑。您应该至少用系统调用号码的符号名(例如,sys\u write
)来注释代码。您可以使用这样一个事实,即从输入读取的字符数在sys\u read的eax
中返回。一种方法是使用返回的字符数作为索引来查找最右边的ASCII数字。返回的字符数包括终止字符(0x0a)。这可以通过将mov-ax、[num]
和ax,1
替换为mov-al、[num+eax-2]
和al,1
来实现。这假设缓冲区足够大,可以容纳包括终止字符在内的最长数字。如果您打算对从控制台输入的数字(除偶数/奇数外)执行任何其他操作,您可能需要将返回的字符串转换为整数,并处理该整数。最好对代码进行注释。它将帮助任何不熟悉特定系统呼叫号码的人提供帮助,而无需研究您所在的平台。它还将使您自己的调试更加容易。test al,1
/jnz
的工作原理相同,但代码大小稍小,效率稍高(test/jnz可以宏融合到单个测试中并分支uop,不像BT)<代码>bt r,r/i是有效的,但是:只有一个uop(与第一个参数的内存操作数不同,在这种情况下,它比在内存参数上测试慢得多,因为位索引影响内存地址)。更重要的是,由于2是10的一个因子,所以只需要测试最后一个十进制数字的低位。由于'0'
的ASCII码是0x30,您可以只测试字符串最后一个ASCII字符的低位。您不需要调用atoi,除非您需要测试n%3
或其他不是10的系数的模数。(也就是说,你可以只看最后一个数字来测试n%2
、n%5
和n%10
)。正如我在回答中指出的那样,sub al,30h
不会影响低位,所以你不需要在测试低位之前进行测试。(另外,test al,1
比SHR更有效,并且不会破坏值。)基本上,我回答的全部要点是解释,测试数字的低位会告诉你它是奇数还是偶数。(虽然我在回答问题时花了更多的时间解释为什么只测试ASCII字符串的低位就足够了,而你不能只看低位十进制数字的低位2来判断一个数字是否是4的倍数。)@PeterCordes我喜欢你为帮助人们所做的事,但有时我们需要从OP的代码和描述中去掉这一个问题。试着从字里行间读,因为有时候OP不知道如何表达他的/问题
; We still have num in ECX, because int 0x80 doesn't clobber any regs (except for eax with the return value).
test byte [ecx + eax - 1], 1
jnz odd
... ;OS puts a char in AL.
sub al,30h ;turn an ASCII char to one integer digit
shr al,1 ;Lets see how the flags responds below
jc .odd ;CF is set if the first bit (right-most, bit 0) is 1.
;do Even things
;skip pass .odd
.odd:
;do Odd things
`section .bss
num resb 1
section .data
msg1 db'enter a number',0xa
len1 equ $-msg1
msg2 db' is even',0xa
len2 equ $-msg2
msg3 db'is odd',0xa
len3 equ $-msg3
section .text
global _start
_start:
mov edx,len1
mov ecx,msg1
mov ebx,1
mov eax,4
int 80h
mov ecx,num
mov ebx,0
mov eax,3
int 80h
mov al,[num]
add al,30h
and al,1
jz iseven
jmp isodd
isodd:
mov edx,len3
mov ecx,msg3
mov ebx,1
mov eax,4
int 80h
jmp exit
iseven:
mov edx,len2
mov ecx,msg2
mov ebx,1
mov eax,4
int 80h
jmp exit
exit:
mov eax,1
int 80h`