0

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

我打算读取第一行,将其从字符串转换为整数,将其移动到我将用作计数器的寄存器,然后打印出数组的许多行。我想即使 N=7 并且我在文件的第一行摆弄说 3,如果我打印了 3 行,那么它就可以工作!然而,这并没有奏效。我让它总是打印出一行,这表明我读入并转换为 int 的数字没有正确转换。我尝试在转换后输出此数字,但尝试这样做会导致段错误,令我惊讶!

这是我在 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 程序中借来的,我用来调试的输出代码也是如此。

4

1 回答 1

1

首先,你为什么printf只用一个参数调用?原型printf是:

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

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

您的退出代码应该是:

.L4:  
    popa
    call    exit

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

parseint似乎返回了错误的号码

* 编辑 *


由于您仍然遇到问题parseint,来自fgetsc++ 站点上的文档,您没有阅读全部内容:

换行符使 fgets 停止读取,但它被函数视为有效字符并包含在复制到 str 的字符串中。

因此,正在发生的事情是您告诉fgets读取字节数,当找到 a 并将其添加到缓冲区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
于 2013-09-05T23:24:54.803 回答