主题:将二进制数转化为10进制没有结果
dmt198704
[专家分:30] 发布于 2007-06-04 21:56:00
.386
.MODEL FLAT
ExitProcess PROTO NEAR32 stdcall, dwExitCode:DWORD
INCLUDE io.h
cr EQU 0dh
Lf EQU 0ah
.STACK 4096
.data
value dword 64h
chushu word 10
string byte 32 dup(?),0
.code
dispbx proc NEAR32
lea ebx,string+31
mov ecx,5
again: xor dx,dx
div chushu
cmp ax,0
jz nzero
jz next
nzero: call disp
next:
mov eax,edx
loop again
ret
dispbx endp
disp proc NEAR32
push edx
push eax
mov dx,ax
add dx,30h
mov [ebx],dx
dec ebx
pop eax
pop edx
ret
disp endp
_start:
mov eax,value
call dispbx
output string
invoke exitprocess,0
public _start
end
请各位高手帮忙看一下程序错在哪,并修改正确。小弟很急。我用的是32位。编译器见
附件编译为ml /c /coff ***.asm
连接为link /subsystem:console /entry:start /out:***.exe ***.obj io.obj kernel32.lib
回复列表 (共13个回复)
沙发
liangbch [专家分:1270] 发布于 2007-06-05 20:15:00
楼主写的程序太深奥了,我自己现写了一个程序,请楼主检查。
.386
.model flat ; 32 bit memory model
option casemap :none ; case sensitive
WriteFile PROTO STDCALL:DWORD,:DWORD,:DWORD,:DWORD,:DWORD
ExitProcess PROTO STDCALL:DWORD
includelib user32.lib
includelib kernel32.lib
.const
_cTen dd 10
.data
value dd 64h
.data?
string byte 32 dup(?)
_tmp1 dd ?
.code
_itoa PROC NEAR ;整数转化为字符串,传入参数 eax,转化后的字符串将存储在 string
save_reg:
push ebx
mov ebx,offset string
next:
xor edx,edx
div dword ptr _cTen
add dl,30h
mov byte ptr [ebx],dl
inc ebx
or eax,eax
jnz next
mov byte ptr [ebx],0 ;写入字符串结束标记,该语句可以省略
;以下代码计算字符串的长度
mov edx,ebx
mov eax,offset string ;edx:字符串开始抵制,ebx:字符串尾地址
sub edx,eax
push edx ;字符串长度入栈
dec ebx
mov edx,offset string ;edx:字符串开始地址,ebx:字符串尾地址
;以下代码翻转字符串,如string="12345",则翻转后变为"54321"
inverse:
mov al,byte ptr [edx]
mov ah,byte ptr [ebx]
mov byte ptr [edx],ah
mov byte ptr [ebx],al
inc edx
dec ebx
cmp edx,ebx
jb inverse
pop eax ;返回字符串的长度到eax
restore_reg:
pop ebx ;恢复ebx寄存器
ret 0
_itoa endp
_main PROC NEAR ; COMDAT
mov eax,value
call _itoa
invoke WriteFile,7,OFFSET string,eax,OFFSET _tmp1,0 ;写字符串到控制台
xor eax, eax
invoke ExitProcess,eax
ret
_main ENDP
public string
public _tmp1
end _main
板凳
dmt198704 [专家分:30] 发布于 2007-06-07 01:27:00
我学的是外国汇编语言教材,是<<80x86汇编语言与计算机体系结构>>.我们学的全是32位指令,你写的我看不懂。麻烦你写一个原序输出十进制数的程序
3 楼
liangbch [专家分:1270] 发布于 2007-06-07 10:38:00
我写的也全是32位指令呀,你应该首先用你的编译器编译一下(编译参数和你的方法相同,也是编译成控制台程序),看看执行结果是否确。
我写的程序确实是一个原序输出10进制字符串的例子。算法大抵是这样的。
比如:一个数是347,
首先将347除以10,得到余数7,加上‘0‘,得到'7', 商为34
然后将34除以10,得到余数4,加上‘0‘, 得到'4', 商为3
最后将3除以10,得到余数3,加上‘0‘, 得到'3', 商为0,循环结束
由于得到的数字是从 个位 到 百位 的顺序,所以,需要反序。将“743"变成"347",然后将整个字符串输出到控制台。
4 楼
liangbch [专家分:1270] 发布于 2007-06-07 11:06:00
如果看看对数转化为串(可以是2,8,10,16进制)不太熟悉的话,我给出我早些日子写的一个程序,希望对你有所帮助。
//一个数转化为一个rad进制形式的字符串,rad可以是2,8,10,或者16
//string:目标字符串地址
void Num2DecString(int n, char *string,int rad)
{
char buff[48];
int i,len;
//-----------------------------
len=0;
if (n==0)
{
string[0]='0';
string[1]=0;
return;
}
while (n >0)
{
buff[len]= (n % rad)+'0';
if (buff[len]>'9') //仅当转化为16进制时
buff[len]+=7; //如果超过'9',转化为"A'-'F'之间的数
len++;
n= n / rad;
}
// 到此为止,buff 存储的是一个反序存储的rad进制形式的字符串,下面的代码将其颠倒过来
for (i=0;i<len;i++)
string[i]=buff[len-1-i];
string[len]=0;
}
5 楼
liangbch [专家分:1270] 发布于 2007-06-07 11:50:00
这个程序更简单一些,他按照从后往前的顺序依次存放各位数字,省去了字符串倒序这一过程,下面给出代码:
.386
.model flat ; 32 bit memory model
option casemap :none ; case sensitive
WriteFile PROTO STDCALL:DWORD,:DWORD,:DWORD,:DWORD,:DWORD
ExitProcess PROTO STDCALL:DWORD
includelib user32.lib
includelib kernel32.lib
.const
_cTen dd 10
.data
value dd 64h
.data?
string byte 32 dup(?)
_tmp1 dd ?
.code
;将整数转化为一个10进制的字符串,传入参数eax,转化后的存储在ebx所示的位置,字符串长度为eax
_itoa PROC NEAR
mov ebx,offset string
add ebx,31 ; ebx= string +31,string ´®µÄβ²¿
push ebx ; 字符串末地址入栈
next:
xor edx,edx
div dword ptr _cTen
add dl,30h
mov byte ptr [ebx],dl
dec ebx ;按照从后往前的顺序存放,故ebx-1
or eax,eax ;如果商不为0,则继续循环
jnz next
pop eax ;从栈中取出字符串的末地址
sub eax,ebx ;得到字符串的实际长度
inc ebx ;得到字符串的首地址
ret 0
_itoa endp
_main PROC NEAR
mov eax,value
call _itoa
;调用win32API函数将字符串写到控制台,7:控制台句柄,ebx:字符串首地址,eax,字符串长度
invoke WriteFile,7,ebx,eax,OFFSET _tmp1,0
xor eax, eax
invoke ExitProcess,eax
ret
_main ENDP
public string
public _tmp1
end _main
6 楼
dmt198704 [专家分:30] 发布于 2007-06-07 13:55:00
按liangbch的程序来试,文件能编译,但连接提示错误:unresolved external symbol _start,请各位高手改正一下错误,我把liangbch的程序最后改为
_main ENDP
_start:
public string
public _tmp1
public _start
end
程序能编译和连接,但运行之后出现***.exe出现问题需要关闭,我用C++调试,出现user breakpoint called from code :
int 3
push ebp
mov ebp,esp
push eax
push ebx
请各位高手指点
7 楼
dmt198704 [专家分:30] 发布于 2007-06-07 13:57:00
按liangbch的程序来试,文件能编译,但连接提示错误:unresolved external symbol _start,请各位高手改正一下错误,我把liangbch的程序最后改为
_main ENDP
_start:
public string
public _tmp1
public _start
end
程序能编译和连接,但运行之后出现***.exe出现问题需要关闭,我用C++调试,出现user breakpoint called from code :
int 3
push ebp
mov ebp,esp
push eax
push ebx
请各位高手指点
8 楼
liangbch [专家分:1270] 发布于 2007-06-07 14:39:00
看来,你对汇编器和链接器的用法不太熟悉,你是不是这么输入的:link /subsystem:console /entry:start
entry:参数是指定入口地址的,我的程序没有定义_start,当然不能链接通过了。你应该将/entry:start 改为/entry:_main.
如果你想在程序中加_start,也不应该加到程序末,应该加到 _main 函数开始:
_main PROC NEAR
_start:
mov eax,value
...
另外,你的参数也太复杂了,我输入的编译链接命令是:
ml /c /coff xxx.asm
link /subsystem:console xxx
xxx.asm为 汇编程序文件名
不知道你的编译器和链接器是否和我的一样:
我的编译器和链接器版本见下:
E:\lbc\test\programfan_236285>ml
Microsoft (R) Macro Assembler Version 6.15.8803
Copyright (C) Microsoft Corp 1981-2000. All rights reserved.
E:\lbc\test\programfan_236285>link
Microsoft (R) Incremental Linker Version 6.00.8168
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.
9 楼
dmt198704 [专家分:30] 发布于 2007-06-07 23:59:00
源程序中pop eax我不太懂,eax开始没有入栈,它为什麽是字符串的末地址。我将 ;调用win32API函数将字符串写到控制台,7:控制台句柄,ebx:字符串首地址,eax,字符串长度
invoke WriteFile,7,ebx,eax,OFFSET _tmp1,0
xor eax, eax
invoke ExitProcess,eax
删去,添上output string 为什麽不行,我写的源程序如下:
.386
.MODEL FLAT
ExitProcess PROTO NEAR32 stdcall, dwExitCode:DWORD
INCLUDE io.h
cr EQU 0dh
Lf EQU 0ah
.STACK 4096
.const
_cTen DWORD 10
.data
prompt BYTE "Enter a number: ",0
value DWORD 64h
string DWORD 32 dup(?),0
.code
_itoa PROC NEAR32
mov ebx,offset string
add ebx,31; ebx= string +31,string ´®µÄβ²¿
push ebx ; 字符串末地址入栈
next:
xor edx,edx
div DWORD ptr _cTen
add dl,30h
mov BYTE ptr [ebx],dl
dec ebx ;按照从后往前的顺序存放,故ebx-1
cmp eax,0 ;如果商不为0,则继续循环
jnz next
pop eax ;从栈中取出字符串的末地址
sub eax,ebx ;得到字符串的实际长度
inc ebx ;得到字符串的首地址
ret
_itoa endp
_start:
mov eax,value
call _itoa
output string
INVOKE Exitprocess,0
PUBLIC _start
END
程序能运行,但是没有显示。原程序中include io.h文件为:
; IO.H -- header file for I/O macros
; 32-bit version for flat memory model
; R. Detmer last revised 8/2000
.NOLIST ; turn off listing
.386
EXTRN itoaproc:near32, atoiproc:near32
EXTRN dtoaproc:near32, atodproc:near32
EXTRN inproc:near32, outproc:near32
itoa MACRO dest,source,xtra ;; convert integer to ASCII string
IFB <source>
.ERR <missing operand(s) in ITOA>
EXITM
ENDIF
IFNB <xtra>
.ERR <extra operand(s) in ITOA>
EXITM
ENDIF
push ebx ;; save EBX
mov bx, source
push bx ;; source parameter
lea ebx,dest ;; destination address
push ebx ;; destination parameter
call itoaproc ;; call itoaproc(source,dest)
pop ebx ;; restore EBX
ENDM
atoi MACRO source,xtra ;; convert ASCII string to integer in AX
;; offset of terminating character in ESI
IFB <source>
.ERR <missing operand in ATOI>
EXITM
ENDIF
IFNB <xtra>
.ERR <extra operand(s) in ATOI>
EXITM
ENDIF
push ebx ;; save EBX
lea ebx,source ;; source address to EBX
push ebx ;; source parameter on stack
call atoiproc ;; call atoiproc(source)
pop ebx ;; parameter removed by ret
ENDM
dtoa MACRO dest,source,xtra ;; convert double to ASCII string
IFB <source>
.ERR <missing operand(s) in DTOA>
EXITM
ENDIF
IFNB <xtra>
.ERR <extra operand(s) in DTOA>
EXITM
ENDIF
push ebx ;; save EBX
mov ebx, source
push ebx ;; source parameter
lea ebx,dest ;; destination address
push ebx ;; destination parameter
call dtoaproc ;; call dtoaproc(source,dest)
pop ebx ;; restore EBX
ENDM
atod MACRO source,xtra ;; convert ASCII string to integer in EAX
;; offset of terminating character in ESI
IFB <source>
.ERR <missing operand in ATOD>
EXITM
ENDIF
IFNB <xtra>
.ERR <extra operand(s) in ATOD>
EXITM
ENDIF
lea eax,source ;; source address to EAX
push eax ;; source parameter on stack
call atodproc ;; call atodproc(source)
;; parameter removed by ret
ENDM
output MACRO string,xtra ;; display string
IFB <string>
.ERR <missing operand in OUTPUT>
EXITM
ENDIF
IFNB <xtra>
.ERR <extra operand(s) in OUTPUT>
EXITM
ENDIF
push eax ;; save EAX
lea eax,string ;; string address
push eax ;; string parameter on stack
call outproc ;; call outproc(string)
pop eax ;; restore EAX
ENDM
input MACRO dest,length,xtra ;; read string from keyboard
IFB <length>
.ERR <missing operand(s) in INPUT>
EXITM
ENDIF
IFNB <xtra>
.ERR <extra operand(s) in INPUT>
EXITM
ENDIF
push ebx ;; save EBX
lea ebx,dest ;; destination address
push ebx ;; dest parameter on stack
mov ebx,length ;; length of buffer
push ebx ;; length parameter on stack
call inproc ;; call inproc(dest,length)
pop ebx ;; restore EBX
ENDM
.NOLISTMACRO ; suppress macro expansion listings
.LIST ; begin listing
10 楼
liangbch [专家分:1270] 发布于 2007-06-08 09:17:00
1.push ,pop 指令对并不需要寄存器相同,push :将寄存器暂存入栈,pop:将栈顶的数送寄存器,我经常可以看到类似这样的代码:
push eax
pop ebx
他与 mov ebx,eax 是等价的,
本例中入栈的地方是
push ebx ; 字符串末地址入栈
出栈的地方是:
pop eax ;从栈中取出字符串的末地址
2。通过分析你的代码,发现输出到控制台最终调用的是 outproc,这个函数并没有在你的程序中定义,他应该 某一个库中的一个函数,对这个函数,我并不了解,因此,不能给你提供更有用的信息。
3。在这个程序中,转化出来的字符串的首地址是ebx,并不是string,你在调用output是,给的参数却是string,这肯定不会得到正确的结果。
我来回复