输入输出 笔记
汇编没有
printf/scanf,一切 I/O 都通过int 21h(DOS 中断) 来完成。
核心套路:把功能号放ah,把参数放指定寄存器,然后int 21h。
一、单个字符
1.1 输出一个字符
asm
mov ah, 02h ; 功能号:输出字符
mov dl, 'A' ; dl = 要输出的字符(ASCII 码)
int 21h ; 屏幕显示 A输出换行:
asm
mov ah, 02h
mov dl, 0Dh ; 回车 CR
int 21h
mov ah, 02h
mov dl, 0Ah ; 换行 LF
int 21h1.2 输入一个字符
asm
mov ah, 01h ; 功能号:输入字符(会回显到屏幕)
int 21h ; 等待用户按键
; 按下后 al = 输入的字符(ASCII 码)输入完后字符在
al里。比如用户按了3,al= 33h(字符'3'的 ASCII)。
二、字符串
2.1 输出字符串
字符串必须以 $ 结尾($ 本身不会显示):
asm
data segment
msg db "Hello, world!", 0Dh, 0Ah, '$' ; 字符串 + 回车换行 + 结束符
data ends
code segment
assume cs:code, ds:data
main:
mov ax, data
mov ds, ax ; ★ 别忘了初始化 ds
mov ah, 09h ; 功能号:输出字符串
mov dx, offset msg; dx = 字符串首地址
int 21h ; 屏幕显示 Hello, world!
mov ah, 4Ch
int 21h
code ends
end main要点:
- 字符串用
$结尾,不是 0!- 用之前一定要
mov ds, ax初始化数据段
2.2 输入字符串
需要提前准备一个 缓冲区 buf:
buf 结构:
第 0 字节:最多允许输入几个字符(你来定)
第 1 字节:实际输入了几个字符(系统填)
第 2 字节起:输入的字符内容asm
data segment
buf db 20 ; 最多输入 20 个字符
db 0 ; 实际输入长度(系统填)
db 20 dup(0) ; 存放输入内容的空间
data ends
code segment
assume cs:code, ds:data
main:
mov ax, data
mov ds, ax
mov ah, 0Ah ; 功能号:输入字符串
mov dx, offset buf
int 21h ; 等待用户输入,回车结束
; 输入完成后:
; buf+1 = 实际输入的字符数
; buf+2 开始 = 输入的字符
mov ah, 4Ch
int 21h
code ends
end main三、数字输入输出(重点!)
DOS 中断只能处理字符,不能直接输入输出数字。所以:
- 输出数字 = 把数字转成一个个字符再逐个输出
- 输入数字 = 把输入的字符转成数字
3.1 输出一个数字
思路:不断除以 10,取余数 + '0' 变成字符,因为先取到的是个位,所以用栈倒序输出。
asm
; ---- 输出 ax 中的无符号数(ax = 12345)----
mov ax, 12345
mov bx, 10 ; 除数
xor cx, cx ; cx = 计数器(记录有几位数)
split:
xor dx, dx ; 清零 dx(16位除法要 dx:ax)
div bx ; ax = ax/10(商),dx = ax%10(余数=当前最低位)
push dx ; 把这一位压栈
inc cx ; 位数 +1
cmp ax, 0
jne split ; 商不为 0 就继续拆
print:
pop dx ; 弹出一位(从高位到低位)
add dl, '0' ; 数字 → ASCII 字符
mov ah, 02h
int 21h ; 输出这个字符
loop print ; cx 次如果要输出有符号数,先判断正负:负数就先输出
'-',再对 ax 取反(neg ax)后按无符号输出。
3.2 输入一个数字
思路:逐个读取字符,每读一个就 结果 = 结果 × 10 + (字符 - '0')。
asm
; ---- 从键盘读入一个无符号数 → 结果存在 bx ----
xor bx, bx ; bx = 0(累加结果)
read_digit:
mov ah, 01h
int 21h ; al = 输入字符
cmp al, 0Dh ; 回车?
je read_done ; 是就结束输入
sub al, '0' ; ASCII → 数字('3' - '0' = 3)
xor ah, ah ; ax = al(零扩展)
; bx = bx * 10 + ax
push ax
mov ax, bx
mov cx, 10
mul cx ; dx:ax = bx * 10
mov bx, ax
pop ax
add bx, ax
jmp read_digit
read_done:
; 此时 bx = 输入的数字四、常用输出小模板
输出空格
asm
mov ah, 02h
mov dl, ' '
int 21h输出换行
asm
; 可以写成一个小函数反复调用
newline:
mov ah, 02h
mov dl, 0Dh
int 21h
mov ah, 02h
mov dl, 0Ah
int 21h
ret输出十六进制数(al 的值)
asm
; ---- 输出 al 的高 4 位和低 4 位(两位十六进制)----
mov bl, al ; 备份 al
shr al, 4 ; 取高 4 位
call print_hex_digit
mov al, bl
and al, 0Fh ; 取低 4 位
call print_hex_digit
; ...
print_hex_digit: ; al = 0~15,输出对应十六进制字符
cmp al, 10
jb is_digit
add al, 'A' - 10 ; 10~15 → 'A'~'F'
jmp do_print
is_digit:
add al, '0' ; 0~9 → '0'~'9'
do_print:
mov dl, al
mov ah, 02h
int 21h
ret五、程序退出
每个程序最后都要有:
asm
mov ah, 4Ch ; 功能号:返回 DOS
mov al, 0 ; 返回码(一般写 0)
int 21h简写:
mov ax, 4C00h+int 21h
六、速查表
| 功能 | ah | 参数 | 返回值 | 说明 |
|---|---|---|---|---|
| 输入字符 | 01h | — | al = 字符 | 带回显 |
| 输出字符 | 02h | dl = 字符 | — | |
| 输出字符串 | 09h | ds:dx → 字符串($ 结尾) | — | |
| 输入字符串 | 0Ah | ds:dx → buf | buf+1 = 长度 | buf 第0字节 = 最大长度 |
| 程序退出 | 4Ch | al = 返回码 | — |