回 帖 发 新 帖 刷新版面

主题:将二进制数转化为10进制没有结果

.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个回复)

沙发

楼主写的程序太深奥了,我自己现写了一个程序,请楼主检查。

   .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

板凳

我学的是外国汇编语言教材,是<<80x86汇编语言与计算机体系结构>>.我们学的全是32位指令,你写的我看不懂。麻烦你写一个原序输出十进制数的程序

3 楼

我写的也全是32位指令呀,你应该首先用你的编译器编译一下(编译参数和你的方法相同,也是编译成控制台程序),看看执行结果是否确。
   我写的程序确实是一个原序输出10进制字符串的例子。算法大抵是这样的。

 比如:一个数是347,
   首先将347除以10,得到余数7,加上‘0‘,得到'7', 商为34
   然后将34除以10,得到余数4,加上‘0‘, 得到'4', 商为3
   最后将3除以10,得到余数3,加上‘0‘,  得到'3', 商为0,循环结束

 由于得到的数字是从 个位 到 百位 的顺序,所以,需要反序。将“743"变成"347",然后将整个字符串输出到控制台。






4 楼

如果看看对数转化为串(可以是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 楼

这个程序更简单一些,他按照从后往前的顺序依次存放各位数字,省去了字符串倒序这一过程,下面给出代码:

.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 &acute;&reg;&micro;&Auml;&Icirc;&sup2;&sup2;&iquest;
    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 楼

按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 楼

按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 楼

看来,你对汇编器和链接器的用法不太熟悉,你是不是这么输入的: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 楼

源程序中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 &acute;&reg;&micro;&Auml;&Icirc;&sup2;&sup2;&iquest;
    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 楼

1.push ,pop 指令对并不需要寄存器相同,push :将寄存器暂存入栈,pop:将栈顶的数送寄存器,我经常可以看到类似这样的代码:
  push eax
  pop ebx
他与 mov ebx,eax  是等价的,

本例中入栈的地方是
   push  ebx    ; 字符串末地址入栈
出栈的地方是:
    pop  eax    ;从栈中取出字符串的末地址

  2。通过分析你的代码,发现输出到控制台最终调用的是 outproc,这个函数并没有在你的程序中定义,他应该 某一个库中的一个函数,对这个函数,我并不了解,因此,不能给你提供更有用的信息。

  3。在这个程序中,转化出来的字符串的首地址是ebx,并不是string,你在调用output是,给的参数却是string,这肯定不会得到正确的结果。


我来回复

您尚未登录,请登录后再回复。点此登录或注册