2025年4月14日 星期一 乙巳(蛇)年 正月十五 设为首页 加入收藏
rss
您当前的位置:首页 > 计算机 > 编程开发 > 汇编

汇编语言结构嵌套简述[附带实例]

时间:03-05来源:作者:点击数:47

结构还可以包含其他结构的实例。例如,Rectangle 可以用其左上角和右下角来定义,而它们都是 COORD 结构:

Rectangle STRUCT
    UpperLeft COORD <>
    LowerRight COORD <>
Rectangle ENDS

Rectangle 变量可以被声明为不覆盖或者覆盖单个 COORD 字段。各种表达形式如下所示:

rect1 Rectangle < >
rect2 Rectangle { }
rect3 Rectangle { {10,10}, {50,20} }
rect4 Rectangle < <10,10>, <50,20> >

下面是对其一个结构字段的直接引用:

mov rect1.UpperLeft.X, 10

也可以用间接操作数访问结构字段。下例用 ESI 指向结构,并把 10 送人该结构左上角的 Y 坐标:

mov esi,OFFSET rect1
mov (Rectangle PTR [esi]).UpperLeft.Y, 10

OFFSET 运算符能返回单个结构字段的指针,包括嵌套字段:

mov edi,OFFSET rect2.LowerRight
mov (COORD PTR [edi]).X, 50
mov edi,OFFSET rect2.LowerRight.X
mov WORD PTR [edi], 50

示例:醉汉行走

现在来看一个使用结构的小程序将会有所帮助。下面完成一个“醉汉行走”练习,用程序模拟一个不太清醒的教授从计算机科学假期聚会回家的路线。利用随机数生成器,选择该教授每一步行走的方向。假设教授处于一个虚构的网格中心,其中的每个方格代表的是北、南、东、西方向上的一步。现在按照随机路径通过网格,如下图所示。 

醉汉行走的示例路径

本程序将使用 COORD 结构追踪这个人行走路径上的每一步,它们被保存在一个 COORD 对象数组中。

WalkMax == 50
DrunkardWalk STRUCT
    path COORD WalkMax DUP(<0, 0>)
    pathsUsed WORD 0
DrunkardWalk ENDS

Walkmax 是一个常数,决定在模拟中教授能够行走的总步数。pathsUsed 字段表示在程序循环结束后,一共行走了多少步。教授每走一步,其位置就被记录在 COORD 对象中,并插入 path 数组下一个可用的位置。程序将在屏幕上显示这些坐标。

以下是完整的程序清单, 需在 32 位模式下运行:

  • ; 醉汉行走 (Walk. asm)
  • ; 醉汉行走程序。教授的起点坐标为(25,25),并在周围徘徊
  • INCLUDE Irvine32.inc
  • WalkMax = 50
  • StartX = 25
  • StartY = 25
  • DrunkardWalk STRUCT
  • path COORD WalkMax DUP(<0,0>)
  • pathsUsed WORD 0
  • DrunkardWalk ENDS
  • DisplayPosition PROTO currX:WORD, currY:WORD
  • .data
  • aWalk DrunkardWalk <>
  • .code
  • main PROC
  • mov esi,OFFSET aWalk
  • call TakeDrunkenWalk
  • exit
  • main ENDP
  • ;-------------------------------------------------------
  • TakeDrunkenWalk PROC
  • LOCAL currX:WORD, currY:WORD
  • ;
  • ; 向随机方向行走(北, 南, 东, 西)
  • ; 接收: ESI 为 DrunkardWalk 结构的指针
  • ; 返回: 结构初始化为随机数
  • ;-------------------------------------------------------
  • pushad
  • ; 用 OFFSET 运算符获取 path,COORD 对象数组的地址,并将其复制到 EDI.
  • mov edi,esi
  • add edi,OFFSET DrunkardWalk.path
  • mov ecx,WalkMax ; 循环计数器
  • mov currX,StartX ; 当前 X 的位置
  • mov currY,StartY ; 当前 Y 的位置
  • Again:
  • ; 把当前位置插入数组
  • mov ax,currX
  • mov (COORD PTR [edi]).X,ax
  • mov ax,currY
  • mov (COORD PTR [edi]).Y,ax
  • INVOKE DisplayPosition, currX, currY
  • mov eax,4 ; 选择一个方向 (0-3)
  • call RandomRange
  • .IF eax == 0 ; 北
  • dec currY
  • .ELSEIF eax == 1 ; 南
  • inc currY
  • .ELSEIF eax == 2 ; 西
  • dec currX
  • .ELSE ; 东 (EAX = 3)
  • inc currX
  • .ENDIF
  • add edi,TYPE COORD ; 指向下一个 COORD
  • loop Again
  • Finish:
  • mov (DrunkardWalk PTR [esi]).pathsUsed, WalkMax
  • popad
  • ret
  • TakeDrunkenWalk ENDP
  • ;-------------------------------------------------------
  • DisplayPosition PROC currX:WORD, currY:WORD
  • ; 显示当前 X 和 Y 的位置
  • ;-------------------------------------------------------
  • .data
  • commaStr BYTE ",",0
  • .code
  • pushad
  • movzx eax,currX ; 当前 X 的位置
  • call WriteDec
  • mov edx,OFFSET commaStr ; "," 字符串
  • call WriteString
  • movzx eax,currY ; 当前 Y 的位置
  • call WriteDec
  • call Crlf
  • popad
  • ret
  • DisplayPosition ENDP
  • END main

现在进一步查看 TakeDrunkenWalk 过程。过程接收指向 DrunkardWalk 结构的指针 (ESI),利用 OFFSET 运算符计算 path 数组的偏移量,并将其复制到 EDI:

mov edi,esi
add edi,OFFSET DrunkardWalk.path

教授初始位置的 X 和 Y 值 (StartX 和 StartY) 都被设置为 25,位于 50 x 50 虚拟网格的中点。循环计数器也进行了初始化:

mov ecx, WalkMax  ;循环计数器
mov currX, StartX    ;当前 X 的位置
mov currY, StartY    ;当前 Y 的位置

循环开始时,对 path 数组的第一项进行初始化:

Again:
    ; 把当前位置插入数组
    mov ax,currX
    mov (COORD PTR [edi]).X,ax
    mov ax,currY
    mov (COORD PTR [edi]).Y,ax

路径结束时,在 pathsUsed 字段插入一个计数值,表示总共走了多少步:

Finish:
    mov (DrunkardWalk PTR [esi]).pathsUsed, WalkMax

在当前的程序中,pathsUsed 总是等于 WalkMaX。不过,若在行走过程中发现障碍,如湖泊或建筑物,情况就会发生变化,循环将会在达到 WalkMax 之前结束。

方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门