NASM的初学者问题:从字符串转换为数字,然后输出到控制台

时间:2013-09-05 20:26:41

标签: nasm

我刚刚开始学习NASM,我正在做一个涉及文本文件中矩阵的第一个程序。该文件包含N * N矩阵,其中第一行包含N,其他每行包含矩阵的一行。为了开始完成我的大任务,我借用了一些逐行读取文件的代码,并将每一行输出到控制台。

我打算在第一行读取,将其从字符串转换为整数,将其移动到我将用作计数器的寄存器,然后打印出该行的那么多行。我想即使N = 7,我也会说文件的顶行说3,如果我打印3行就可以了!但是,这不起作用。我得到它总是打印出一行,表明我读入并转换为int的数字未正确转换。我试图在转换后输出这个数字,但试图这样做会导致一个seg错误,让我感到惊讶!

这是我在Linux下的NASM代码:

; this program demonstrates how to open files for reading
; It reads a text file line by line and displays it on the screen

extern fopen
extern fgets
extern fclose
extern printf
extern exit

global main

segment .data
readmode: db "r",0
filename: db "hw6_1.dat",0 ; filename to open
error1:   db "Cannot open file",10,0
format_1: db "%d",0

segment .bss
buflen:   equ 256         ; buffer length
buffer:   resd buflen     ; input buffer

segment .text
main: pusha
; OPENING FILE FOR READING  
push readmode       ; 1- push pointer to openmode   
push filename       ; 2- push pointer to filename
call fopen          ; fopen retuns a filehandle in eax
add esp, 8          ;   or 0 if it cannot open the file
cmp eax, 0          
jnz .L1             
push error1         ; report an error and exit
call printf
add esp, 4
jmp .L4

; READING FROM FILE     
.L1:  mov ebx, eax        ; save filepointer of opened file in ebx

; Get first line and pass to ecx
push ebx
push dword buflen
push buffer
call fgets
add esp, 12
cmp eax, 0
je .L3

;convert string -> numeric
push buffer
call parseInt
mov ecx, eax

.L2:  
;debug
push ecx
push format_1
call printf
add esp, 8

push ebx            ; 1- push filehandle for fgets
push dword buflen   ; 2- push max number of read chars
push buffer         ; 3- push pointer to text buffer
call fgets          ; get a line of text        
add esp, 12         ; clean up the stack
cmp eax, 0          ; eax=0 in case of error or EOF
je .L3
push buffer         ; output the read string
call printf
add esp, 4          ; clean up the stack
dec ecx
cmp ecx, 0
jg .L2

;CLOSING FILE  
.L3:  push ebx            ; push filehandle 
call fclose         ; close file
add esp, 4          ; clean up stack

.L4:  popa
call exit

parseInt:   
push ebp
mov ebp, esp
push ebx
push esi
mov esi, [ebp+8]        ; esi points to the string

xor eax, eax            ; clear the accumulator
.I1   cmp byte [esi], 0       ; end of string?
je .I2
mov ebx, 10
mul ebx                 ; eax *= 10
xor ebx, ebx
mov bl, [esi]           ; bl = character
sub bl, 48              ; ASCII conversion
add eax, ebx
inc esi
jmp .I1

.I2:   pop esi
pop ebx
pop ebp
ret 4

示例数据文件如下所示,这是我正在使用的文件:

4
2 45 16 22
17 21 67 29
45 67 97 35
68 34 90 72

我真的不明白这是怎么回事。转换为整数的代码是从WORKING程序借来的,就像我用来调试的输出代码一样。

1 个答案:

答案 0 :(得分:1)

首先,为什么只用一个参数调用printfprintf的原型是:

int printf ( const char * format, ... );

其次,你的程序工作得很好,你只是没有正确退出程序!您正在链接到c库并添加了启动代码,您需要调用exit而不是ret。实际上,只有ret不是退出Linux或Windows中任何程序的正确方法。

您的退出代码应为:

.L4:  
    popa
    call    exit

并将extern exit添加到您的外部列表中。

您的parseint似乎返回了错误的号码

*编辑*


由于您仍然遇到parseint的问题,来自c ++网站的fgets文档,您并没有阅读整篇文章:

  

换行符使fgets停止读取,但它被认为是a   函数的有效字符和复制到的字符串中的包含   海峡

所以,正在发生的事情是你告诉fgets读取dword buflen个字节数,它会在找到newline时停止读取并将其添加到缓冲区。

此:

; Get first line and pass to ecx
push ebx
push dword buflen
push buffer
call fgets
add esp, 12

应该是:

; Get first line and pass to ecx
push ebx
push 1     ; <----- you only want to read 1 byte!
push buffer
call fgets
add esp, 12