在嵌入式开发或底层驱动编程中,经常需要直接操作硬件端口。这时候,用高级语言可能显得太“重”,而汇编语言则能精准控制每一个字节。数组作为最基本的数据结构,在汇编里并不是像C语言那样写个 int arr[5] 就完事了,它得靠程序员自己规划内存布局。
数组的本质是连续内存
汇编语言没有内置的“数组”类型,但它的核心思想很简单:一组相同类型的数据连续存放在内存中。比如你要存储5个字节的数据,可以手动分配一段内存空间,然后通过基地址加偏移的方式来访问每个元素。
DATA SEGMENT
my_array DB 10h, 20h, 30h, 40h, 50h ; 定义一个字节数组
array_size EQU 5 ; 数组长度符号定义
DATA ENDS
这里用 DB(Define Byte)声明了五个十六进制数值,它们在内存中紧挨着存放。假设 my_array 的起始地址是 0x1000,那么第3个元素就在 0x1002 处,访问时可以用寄存器做地址计算。
用寄存器索引数组元素
实际使用中,通常会把数组首地址加载到某个寄存器,比如 SI,再用 BX 或 CX 当作索引。例如要读取第 i 个元素:
MOV SI, OFFSET my_array ; SI 指向数组首地址
MOV BX, 2 ; 假设要访问第3个元素(从0开始)
XOR AL, AL ; 清空AL
MOV AL, [SI + BX] ; 取出my_array[2]的值
这种写法在处理端口映射时特别有用。比如你有一组I/O端口地址要依次访问,完全可以把这些地址预先存成“数组”,然后循环遍历。
数组与端口映射的实际结合
设想一个场景:你正在调试一块老式工业控制板,上面有8个LED灯,分别连接到不同的I/O端口,地址从 0x300 到 0x307。你想让这些灯按顺序闪烁,最笨的办法是写8条 out 指令。更聪明的方式是把端口地址做成数组,用循环处理。
PORTS SEGMENT
port_list DW 300h, 301h, 302h, 303h, 304h, 305h, 306h, 307h
PORTS ENDS
CODE SEGMENT
MOV CX, 8 ; 循环8次
MOV SI, OFFSET port_list
MOV BX, 0 ; 索引起始为0
>loop_start:
MOV DX, [SI + BX] ; 取出当前端口地址
MOV AL, 0FFh ; 输出高电平点亮LED
OUT DX, AL
> ; 此处可加入延时
> INC BX ; 移动到下一个端口
LOOP loop_start
CODE ENDS
这样代码简洁多了,也方便后期修改。如果哪天硬件改了接线,只需要调整 port_list 里的数值,不用动逻辑。
多维数组怎么搞?
虽然汇编不支持二维数组语法,但可以用一维模拟。比如一个 2x3 的字节数组,总共6个元素:
matrix DB 1,2,3
DB 4,5,6
访问 matrix[1][2] 相当于找第 (1*3 + 2) = 5 个元素,也就是偏移量+5。只要算好行宽,就能像C语言一样用公式 index = row * width + col 来定位。
这种技巧在配置多个设备寄存器时很实用。比如一组传感器各有3个控制寄存器,你可以按设备顺序排布成“二维表”,运行时动态计算地址。