结构体的定义
在汇编中定义结构体的基本形式如下:
name STRUCT
;具体定义
name ENDS
具体定义中可以包含以下的内容:
1. 未定义:用“?”表示;
2. 字符串:用双引号包围;
3. 整数:可以是常量或者表达式;
4. 数组:使用DUP操作符来初始化数组;
下面是一个例子:
Employee STRUCT
IdNum BYTE "000000000" ; 9 个字节
Lastname BYTE 30 DUP(0) ; 30 个字节
Years WORD ? ; 2 个字节
SalaryHistory DWORD 0,0,0,0 ; 16 个字节
Employee ENDS ; 共57个字节
上面就是一个汇编结构体的定义,但是它存在一个小问题,即结构体中的某些成员并不是对称的,这在一定程度上会影响到CPU访问成员的速度,因此可以有以下的改进:
Employee STRUCT
Idnum BYTE "000000000" ; 9 个字节
Reserved1 BYTE 0 ; 增加一个字节,使Years能按双字节对齐
Lastname BYTE 30 DUP(0) ; 30 个字节
Years WORD ? ; 2 个字节
Reserved2 WORD 0 ; 增加两个字节,使SalaryHistory能按四字节对齐
SalaryHistory DWORD 0,0,0,0 ; 16 个字节
Employee ENDS ; 共60个字节
另外,还可以使用masm中的伪指令ALIGN来达到相同的目的:
Employee STRUCT
Idnum BYTE "000000000" ; 9 个字节
Lastname BYTE 30 DUP(0) ; 30 个字节
ALIGN WORD ; 增加1个字节,使Years能按双字节对齐
Years WORD ? ; 2 个字节
ALIGN DWORD ; 增加2个字节,使SalaryHistory能按四字节对齐
SalaryHistory DWORD 0,0,0,0 ; 16 个字节
Employee ENDS ; 共60个字节
不过这个伪指令并不是在所有的汇编编译器上都能够使用的,所以还是建议使用前者。
结构体变量的使用
下面是结构体的以下声明:
.data
worker1 EmpLoyee <> ; 未初始化的结构体变量
worker2 Employee <"123456789"> ; 初始化了一部分成员的结构体变量
worker3 Employee <,"John"> ; 初始化了一部分成员的结构体变量2
worker4 Employee {, "Jack"} ; 除了使用<>也可以使用{}
workerCount = 10
department Employee workerCount DUP(<>) ; 结构体数组
以及结构体的一般使用:
.code
main PROC
mov worker1.SalaryHistory, 1000h ; worker1.SalaryHistory本身就是一个内存地址了,
; 所以可以直接传值
mov eax, worker1.SalaryHistory
mov ebx, OFFSET Employee.SalaryHistory ; 通过OFFSET可以得到成员在结构体中的便宜,
; 注意这里需要使用Employee,而不能使用worker1
mov ecx, TYPE Employee ; 通过TYPE可以得到结构体的大小。
call DumpRegs
exit
main ENDP
END main
另一个稍微复杂一点的例子:
.code
main PROC
mov edi, 0 ; 数组偏移,第一次是0
mov ecx, workerCount ; 人数,表示的是循环次数
mov eax, 1 ; 赋的初值,没有特殊意义
L1:
mov (Employee PTR department[edi]).Years, ax ; 因为Years是WORD,所以这里需要使用ax
add edi, TYPE Employee ; 指向像下一个结构体
loop L1 ; 根据ecx中的循环次数做循环,循环的时候会将ecx中的值减1
exit
main ENDP
END main