汇编学习4

汇编实现的用户输入和输出示例

在练习过程中,我做了一个汇编程序,它接收用户输入的两个数字 ab,然后以 a + b = ? 的形式输出结果。在实现过程中,我学习并使用了以下新模块:

  • str_to_int:将字符串转换为整数
  • int_to_str:将整数转换为字符串
  • remove_newline:去除输入中的换行符

为什么需要这些模块?

1. str_to_int 模块

作用:该模块用于将用户输入的字符串转换为整数。用户输入的数据通常以字符串形式存在,因此在进行数学运算之前,需要将其转换为整数
原因:在汇编语言中,输入从标准输入读取时默认是ASCII字符(字符串),无法直接进行数学运算str_to_int 使得程序可以将这些字符转换成整数,便于计算

2. int_to_str 模块

作用:该模块用于将计算结果(整数)转换为字符串,以便程序能够正确输出结果
原因:在汇编中,输出到标准输出时需要数据以字符串形式存在。如果不将整数转换回字符串,就无法显示结果给用户。因此,int_to_str 是必不可少的,将计算后的数值转换成可打印格式

3. remove_newline 模块

作用:用于去除用户输入中的换行符
原因:用户在输入数字时会按下回车键,这会在输入数据中留下一个换行符('\n'),影响字符串到整数的转换。如果不移除换行符,程序在处理输入时可能会出现错误。因此,remove_newline 确保输入字符串格式正确

练习中的挑战

在完成这个小任务时,我遇到了一些问题:

  • 未清空 edx:在存储除法余数之前没有清空 edx,导致结果错误。清空 edx 确保了除法的正确性
  • 未移除换行符:用户输入中残留的换行符导致了转换错误,这让我意识到去除换行符的重要性

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
section .data
plus_sign db '+', 0
equ_sign db '=', 0
newline db 0xA, 0

section .bss
buffer1 resb 64
buffer2 resb 64
result resd 1
num_str resb 64

section .text
global _start

_start:
mov eax, 3
mov ebx, 0
mov ecx, buffer1
mov edx, 64
int 0x80

; 移除换行符并转换为整数
mov esi, buffer1
call remove_newline

mov esi, buffer1
call str_to_int
mov [result], eax

mov eax, 3
mov ebx, 0
mov ecx, buffer2
mov edx, 64
int 0x80

; 移除换行符并转换为整数
mov esi, buffer2
call remove_newline

mov esi, buffer2
call str_to_int

; 将第二个数字加到 result 中
add eax, [result]
mov [result], eax ; 更新 result

mov eax, 4
mov ebx, 1
mov ecx, buffer1
mov edx, 64
int 0x80

mov eax, 4
mov ebx, 1
mov ecx, plus_sign
mov edx, 1
int 0x80

mov eax, 4
mov ebx, 1
mov ecx, buffer2
mov edx, 64
int 0x80

; 打印等号
mov eax, 4
mov ebx, 1
mov ecx, equ_sign
mov edx, 1
int 0x80

; 转换并打印结果
mov eax, [result]
call int_to_str

mov eax, 4
mov ebx, 1
mov ecx, edi
mov edx, 64
int 0x80

mov eax, 4
mov ebx, 1
mov ecx, newline
mov edx, 1
int 0x80

mov eax, 1
xor ebx, ebx
int 0x80

; 将字符串转换为整数的函数
str_to_int:
xor eax, eax ; 清空 eax (存放结果)
xor ebx, ebx ; 清空 ebx (存放当前字符)
str_to_int_loop:
mov bl, [esi] ; 读取当前字符
cmp bl, 0 ; 检查是否到达字符串末尾
je str_to_int_end

cmp bl, '0' ; 检查字符是否为数字
jl str_to_int_end ; 如果小于 '0',跳转到结束
cmp bl, '9'
jg str_to_int_end ; 如果大于 '9',跳转到结束

sub bl, '0' ; 将 ASCII 字符转为对应的数字
imul eax, eax, 10 ; 将当前结果乘以 10
add eax, ebx ; 加上当前数字

inc esi ; 移动到下一个字符
jmp str_to_int_loop
str_to_int_end:
ret

; 将整数转换为字符串的函数
int_to_str:
mov edi, num_str ; 指向结果缓冲区的末尾
add edi, 11 ; 设置指针到缓冲区的末端
mov byte [edi], 0 ; 在缓冲区末尾添加空字符
dec edi ; 指针向前移动一位

mov ecx, 10 ; 除数 10
xor edx, edx ; 清空 edx
xor ebx, ebx ; 清空 ebx
convert_loop:
xor edx, edx ; 清空 edx
div ecx ; 将 eax 除以 10,结果在 eax,余数在 edx
add dl, '0' ; 将余数转换为字符
mov [edi], dl ; 存储字符
dec edi ; 指针前移
inc ebx ; 计数器递增
cmp eax, 0
jnz convert_loop

inc edi
mov edx, ebx
ret

; 去除输入中的换行符的函数
remove_newline:
remove_newline_loop:
mov al, [esi] ; 读取当前字符
cmp al, 0 ; 检查是否到达字符串末尾
je remove_newline_end

cmp al, 0xA ; 检查字符是否为换行符
jne continue_loop
mov byte [esi], 0 ; 将换行符替换为空字符
jmp remove_newline_end
continue_loop:
inc esi ; 移动到下一个字符
jmp remove_newline_loop
remove_newline_end:
ret