【问题标题】:Beginner issues with NASM: converting from string to number, and output to the consoleNASM 的初学者问题:从字符串转换为数字,并输出到控制台
【发布时间】:2013-09-05 20:26:40
【问题描述】:

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

【问题讨论】:

  • 如果您只是打印数据而不使用printf 的任何格式化功能,请改用puts。 (请注意,puts 会自动附加一个换行符。如果您不想这样做,请使用 fputs,但请注意额外的 FILE* 参数。)

标签: nasm


【解决方案1】:

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

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

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

您的退出代码应该是:

.L4:  
    popa
    call    exit

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

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

* 编辑 *


由于您仍然在使用 parseint 时遇到问题,来自 c++ 站点上的 fgets 文档,因此您没有阅读全部内容:

换行符使 fgets 停止读取,但它被认为是 函数的有效字符和 included 在复制到的字符串中 字符串。

所以,发生的事情是您告诉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

【讨论】:

  • 我想我看到了 parseInt 的错误。它必须是一个空终止的字符串,但 dat 文件只有数字作为一个没有空终止的字符串。我被要求不要为文本文件提供不同的格式样式。这意味着我必须修改缓冲区的推送以添加 0 终止符或其他内容。我现在会努力的。
  • 恐怕我错了。根据 cplusplus.com/reference/cstdio/fgets ,“在复制到 str 的字符之后会自动附加一个终止空字符。” ...这意味着有一个终止字符,我借用的将字符串解析为 int 的算法是错误的,即使我看不出它有什么问题!此外,由于我现在正确使用 printf,我知道 parseInt 返回一个大约 250 的数字,具体取决于读取的数字(低得多,如 3 或 4)。然而这个数字是正数,为什么我没有触发“jg L2”条件?
  • 代码已更新以匹配当前。如上所述,parseInt 仍然无法正常工作。
  • 编辑答案以包含修复
  • 实际上我最近在想换行符,这证实了这一点。值得庆幸的是,对于这项任务,第一行的数字始终小于 10。因此,您的解决方案将有效。谢谢!
猜你喜欢
  • 1970-01-01
  • 2022-11-04
  • 1970-01-01
  • 2011-05-16
  • 2012-06-12
  • 2016-11-18
  • 2011-08-13
  • 2019-09-01
  • 1970-01-01
相关资源
最近更新 更多