汇编语言数字处理.md

原始源文件

---
ingested: true
ingestedAt: 2026-05-17
---
标题: 汇编语言 - 数字处理
链接: https://www.runoob.com/assembly/assembly-numbers.html
内容: ## 汇编语言 - 数字处理

在汇编语言中处理数字涉及到进制转换、ASCII 转换和算术运算的结合。本章详细讲解如何在程序中输入和输出各种进制的数字。

---

## 数字的表示方式

计算机内部所有数字都以二进制存储,但程序中可以用不同进制表示:

| 进制   | 基数 | NASM 写法                | 数字范围(32位) |
| ---- | -- | ---------------------- | --------- |
| 二进制  | 2  | 0b10101010 或 10101010b | 0 和 1     |
| 八进制  | 8  | 0o52 或 52o             | 0-7       |
| 十进制  | 10 | 42                     | 0-9       |
| 十六进制 | 16 | 0x2A 或 2Ah             | 0-9, A-F  |

---

## ASCII 与数字的关系

在屏幕上输入和输出的都是 ASCII 字符,而非二进制数值。

理解字符与数值的转换是汇编数字处理的核心:

| 字符  | ASCII 值  | 对应的数值    |
| --- | -------- | -------- |
| '0' | 0x30(48) | 0        |
| '1' | 0x31(49) | 1        |
| '9' | 0x39(57) | 9        |
| 'A' | 0x41(65) | 10(十六进制) |
| 'F' | 0x46(70) | 15(十六进制) |
| 'a' | 0x61(97) | 10(十六进制) |

字符转数字:`数值 = ASCII码 - '0'`(即 `ASCII码 - 0x30`)

数字转字符:`ASCII码 = 数值 + '0'`(即 `数值 + 0x30`)

---

## 输入数字(字符串转数值)

用户输入的是字符序列,需要转换为二进制数值才能用于计算:

## 实例

; 文件路径:string\_to\_int.asm  
; 将十进制数字字符串转换为整数值

section .data  
 input\_str db '12345', 0 ; 输入字符串 "12345"  
 input\_len dd 5 ; 字符串长度

section .bss  
 result\_val resd 1 ; 存放转换后的数值

section .text  
global \_start

\_start:  
; 转换算法:result = 0  
; result = result \* 10 + (当前字符 - '0')  
mov esi, input\_str ; esi 指向输入字符串  
mov ecx, \[input\_len\] ; ecx = 循环次数  
mov eax, 0 ; eax = 累加结果

convert\_loop:  
mov ebx, 10  
mul ebx ; eax = eax \* 10  
; mul ebx: edx:eax = eax \* ebx

mov bl, \[esi\] ; 读取当前字符  
sub bl, '0' ; 转为数值:字符 - '0'  
movzx ebx, bl ; 零扩展 ebx(bl -> ebx)  
add eax, ebx ; eax = eax + 当前位数值

inc esi ; 移动到下一个字符  
loop convert\_loop  
; eax 现在 = 12345

mov \[result\_val\], eax ; 保存结果

mov eax, 1  
mov ebx, 0  
int 0x80  

> 算法解析:以 "12345" 为例:  
> 第1轮:result = 0×10 + 1 = 1  
> 第2轮:result = 1×10 + 2 = 12  
> 第3轮:result = 12×10 + 3 = 123  
> ...最终得到 12345。

---

## 输出数字(数值转字符串)

将二进制数值转为可显示的十进制字符串:

## 实例

; 文件路径:int\_to\_string.asm  
; 将整数值转换为十进制字符串输出

section .data  
 number dd 12345 ; 要输出的数字  
 newline db 0xA

section .bss  
 output\_buf resb 12 ; 输出缓冲区(最大 32 位整数是 10 位 + 符号 + null)

section .text  
global \_start

\_start:  
mov eax, \[number\] ; 加载数字  
mov edi, output\_buf + 11 ; edi 指向缓冲区末尾  
mov byte \[edi\], 0 ; null 终止符(方便调试)  
dec edi

mov ebx, 10 ; 除数 = 10  
mov ecx, 0 ; 位数计数器

convert\_digit:  
mov edx, 0 ; 清零 edx(div 需要 edx:eax)  
div ebx ; eax = eax/10, edx = eax%10  
add dl, '0' ; 余数转字符  
mov \[edi\], dl ; 存入缓冲区(从后往前)  
dec edi ; 缓冲区指针前移  
inc ecx ; 位数 +1  
cmp eax, 0 ; 商是否为 0?  
jne convert\_digit ; 否,继续循环

; 现在 edi+1 指向第一个有效数字字符  
inc edi ; 修正指针,指向字符串开头

; 计算有效字符长度  
; output\_buf + 11 - edi 即有效长度

; 输出数字  
mov eax, 4  
mov ebx, 1  
mov ecx, edi ; 指向转换后的字符串  
; 计算长度  
mov edx, output\_buf + 11  
sub edx, edi ; edx = 缓冲区末尾 - 字符串开头  
int 0x80

; 输出换行  
mov eax, 4  
mov ebx, 1  
mov ecx, newline  
mov edx, 1  
int 0x80

mov eax, 1  
mov ebx, 0  
int 0x80  

运行结果:

$ nasm -f elf32 int_to_string.asm -o int_to_string.o
$ ld -m elf_i386 int_to_string.o -o int_to_string
$ ./int_to_string
12345

---

## 十六进制输入输出

处理十六进制需要同时处理 0-9 和 A-F/a-f 的转换:

## 实例

; 文件路径:hex\_output.asm  
; 将数值以十六进制格式输出

section .data  
 number dd 0x1A2B3C4D ; 要输出的值  
 hex\_prefix db '0x'  
 hex\_prefix\_len equ $ \- hex\_prefix  
 newline db 0xA

section .bss  
 hex\_buf resb 10 ; 8 个十六进制位 + 前缀 + null

section .text  
global \_start

\_start:  
; 输出前缀 "0x"  
mov eax, 4  
mov ebx, 1  
mov ecx, hex\_prefix  
mov edx, hex\_prefix\_len  
int 0x80

mov eax, \[number\] ; 要转换的数值  
mov edi, hex\_buf + 8 ; 缓冲区末尾(8 个十六进制位)  
mov ecx, 8 ; 循环 8 次(32 位 = 8 个十六进制位)

hex\_loop:  
mov edx, 0 ; 准备除法  
mov ebx, 16 ; 除以 16  
div ebx ; 现在:eax 除以 ebx  
; 注意:这里 div ebx 实际是 edx:eax / ebx  
; 余数在 edx(0-15),商在 eax  
mov ebx, eax ; 保存商

; 将余数转为十六进制字符  
mov al, dl  
cmp al, 10  
jl digit\_09 ; 0-9  
add al, 'A' \- 10 ; A-F  
jmp store\_char

digit\_09:  
add al, '0' ; 0-9

store\_char:  
dec edi  
mov \[edi\], al  
mov eax, ebx ; 恢复商  
loop hex\_loop

; 移除了loop,直接使用递减方式

; 输出十六进制数字(8 位)  
mov eax, 4  
mov ebx, 1  
mov ecx, hex\_buf  
mov edx, 8  
int 0x80

; 输出换行  
mov eax, 4  
mov ebx, 1  
mov ecx, newline  
mov edx, 1  
int 0x80

mov eax, 1  
mov ebx, 0  
int 0x80  

---

## 完整示例:简单的加法计算器

从键盘输入两个一位数,计算它们的和并输出:

## 实例

; 文件路径:simple\_calc.asm  
; 输入两个一位数(0-9),计算和并输出

section .data  
 prompt1 db 'Enter first number (0-9): '  
 prompt1\_len equ $ \- prompt1  
 prompt2 db 'Enter second number (0-9): '  
 prompt2\_len equ $ \- prompt2  
 result\_msg db 'Sum = '  
 result\_msg\_len equ $ \- result\_msg  
 newline db 0xA

section .bss  
 num1 resb 2 ; 第一个数的输入(1位+换行)  
 num2 resb 2 ; 第二个数的输入  
 result\_str resb 3 ; 结果字符串(最多2位+换行)

section .text  
global \_start

\_start:  
; 提示输入第一个数  
mov eax, 4  
mov ebx, 1  
mov ecx, prompt1  
mov edx, prompt1\_len  
int 0x80

; 读取第一个数  
mov eax, 3  
mov ebx, 0  
mov ecx, num1  
mov edx, 2  
int 0x80

; 提示输入第二个数  
mov eax, 4  
mov ebx, 1  
mov ecx, prompt2  
mov edx, prompt2\_len  
int 0x80

; 读取第二个数  
mov eax, 3  
mov ebx, 0  
mov ecx, num2  
mov edx, 2  
int 0x80

; 计算和  
mov al, \[num1\] ; 读取第一个数(ASCII 字符)  
sub al, '0' ; 转为数值  
mov bl, \[num2\] ; 读取第二个数  
sub bl, '0' ; 转为数值  
add al, bl ; 求和

; 将结果转为字符串  
mov ah, 0 ; 准备除法  
mov bl, 10 ; 除以 10  
div bl ; al = 十位数, ah = 个位数

; 保存结果  
add al, '0' ; 十位转字符  
mov \[result\_str\], al ; 存十位  
add ah, '0' ; 个位转字符  
mov \[result\_str + 1\], ah ; 存个位  
mov byte \[result\_str + 2\], 0xA ; 换行

; 输出结果信息  
mov eax, 4  
mov ebx, 1  
mov ecx, result\_msg  
mov edx, result\_msg\_len  
int 0x80

; 输出计算结果(可能 1 或 2 位)  
mov eax, 4  
mov ebx, 1  
mov ecx, result\_str  
cmp byte \[result\_str\], '0'  
je output\_one\_digit ; 如果十位是 '0',只输出个位  
mov edx, 3 ; 2 位 + 换行  
jmp do\_output

output\_one\_digit:  
inc ecx ; 跳过十位的 '0'  
mov edx, 2 ; 1 位 + 换行

do\_output:  
int 0x80

mov eax, 1  
mov ebx, 0  
int 0x80  

运行结果:

$ nasm -f elf32 simple_calc.asm -o simple_calc.o
$ ld -m elf_i386 simple_calc.o -o simple_calc
$ ./simple_calc
Enter first number (0-9): 7
Enter second number (0-9): 8
Sum = 15

> 在汇编中处理数字输入输出需要对 ASCII 编码和进制转换有清晰的理解。数字转字符串(int to string)和字符串转数字(string to int)是最基本的两个工具函数,建议写好后保存为模板,后续可直接复用。