汇编语言TYPE和SIZEOF运算符:引用结构变量和结构名称
使用 TYPE 和 SIZEOF 运算符可以引用结构变量和结构名称。例如,现在回到之前的 Employee 结构:
Employee STRUCT IdNum BYTE "000000000" ; 9 LastName BYTE 30 DUP(0) ; 30 ALIGN WORD ; 加 1 字节 Years WORD 0 ; 2 ALIGN DWORD ; 加 2 字节 SalaryHistory DWORD 0,0,0,0 ; 16 Employee ENDS ; 共 60 字节给定数据定义:
.data
worker Employee <>
TYPE Employee ; 60
SIZEOF Employee ; 60
SIZEOF worker ; 60
1) 引用成员
引用已命名的结构成员时,需要用结构变量作为限定符。以 Employee 结构为例,在汇编时能生成下述常量表达式:
TYPE Employee.SalaryHistory ; 4
LENGTHOF Employee.SalaryHistory ; 4
SIZEOF Employee.SalaryHistory ; 16
TYPE Employee.Years ; 2
.data worker Employee <> .code mov dx,worker.Years mov worker.SalaryHistory, 20000 ;第一个工资 mov [worker.SalaryHistory+4 ], 30000 ;第二个工资使用 OFFSET 运算符能获得结构变量中一个字段的地址:
mov edx,OFFSET worker.LastName
2) 间接和变址操作数
间接操作数用寄存器(如 ESI)对结构成员寻址。间接寻址具有灵活性,尤其是在向过程传递结构地址或者使用结构数组的情况下。引用间接操作数时需要 PTR 运算符:
mov esi,OFFSET worker
mov ax,(Employee PTR [esi]).Years
mov ax, [esi].Years ;无效
变址操作数
用变址操作数可以访问结构数组。假设 department 是一个包含 5 个 Employee 对象的数组。下述语句访问的是索引位置为 1 的雇员的 Years 字段:.data department Employee 5 DUP(<>) .code mov esi, TYPE Employee ; 索引 = 1 mov department[esi].Years, 4
数组循环
带间接或变址寻址的循环可以用于处理结构数组。下面的程序 (AllPoints.asm)为 AllPoints 数组分配坐标:; 数组循环 (AllPoints.asm) INCLUDE Irvine32.inc NumPoints = 3 .data ALIGN WORD AllPoints COORD NumPoints DUP(<0,0>) .code main PROC mov edi,0 ; 数组索引 mov ecx,NumPoints ; 循环计数器 mov ax,1 ; 起始 X, Y 的值 L1: mov (COORD PTR AllPoints[edi]).X,ax mov (COORD PTR AllPoints[edi]).Y,ax add edi,TYPE COORD inc ax loop L1 exit main ENDP END main
3) 对齐的结构成员的性能
之前已经断言,处理器访问正确对齐的结构成员时效率更高。那么,非对齐字段会对性能产生多大影响呢?现在使用本章介绍的 Employee 结构的两种不同版本,进行一个简单的测试。测试将对第一个版本进行重命名,以便两种版本能在同一个程序中使用:EmployeeBad STRUCT Idnum BYTE "000000000" Lastname BYTE 30 DUP(0) Years WORD 0 SalaryHistory DWORD 0,0,0,0 EmployeeBad ENDS Employee STRUCT Idnum BYTE "000000000" Lastname BYTE 30 DUP(0) ALIGN WORD Years WORD 0 ALIGN DWORD SalaryHistory DWORD 0,0,0,0 Employee ENDS下面的代码首先获取系统时间,再执行循环以访问结构字段,最后计算执行花费的时 间。变量 emp 可以声明为 Employee 对象或者 EmployeeBad 对象:
.data ALIGN DWORD startTime DWORD ? ; 对齐 startTime emp EmployeeBad <> ; 或: EmployeeBad .code call GetMSeconds ; 获取系统时间 mov startTime,eax mov ecx,0FFFFFFFFh ; 循环计数器 L1: mov emp.Years,5 mov emp.SalaryHistory,35000 loop L1 call GetMSeconds ; 获取开始时间 sub eax,startTime call WriteDec ; 显示执行花费的时间在这个简单的测试程序中,使用正确对齐的 Employee 结构的执行时间为 6141 毫秒,而使用 EmployeeBad 结构的执行时间为 6203 毫秒。两者相差不大 (62 毫秒),可能是因为处理器的内存 cache 将对齐问题最小化了。