以下是Kip Irvine的汇编语言x86书中的链表汇编程序。在main中,循环遍历列表并显示所有节点值。程序不是使用固定计数器进行循环,而是检查尾节点中的空指针,并在找到它时停止循环。我的问题如下:
(a)有人可以解释<计数器,($ +计数器* SIZEOF ListNode)>?它是如何工作的,它意味着什么?
(b)有人可以解释(ListNode PTR [esi])。NextPtr?这是什么意思?
INCLUDE Irvine32.inc
ListNode STRUCT
NodeData DWORD ?
NextPtr DWORD ?
ListNode ENDS
TotalNodeCount = 15
NULL = 0
Counter = 0
.data
putc macro ptr
push eax
mov al, ptr
call writechar
pop eax
endm
;to use:
;putc 'a'
LinkedList LABEL PTR ListNode
REPEAT TotalNodeCount
Counter = Counter + 1
ListNode <Counter, ($ + Counter * SIZEOF ListNode)>
;struct variables Counter, and ($+Counter*SIZEOF ListNode) being declared
;
ENDM
ListNode <0,0> ; tail node
.code
main PROC
mov esi,OFFSET LinkedList
; Display the integers in the NodeData fields.
NextNode:
; Check for the tail node.
putc 'a'; ->first node, then third node
mov eax,(ListNode PTR [esi]).NextPtr
cmp eax,NULL
je quit
; Display the node data.
putc 'b' ;->fourth node
mov eax,(ListNode PTR [esi]).NodeData
call WriteDec
call Crlf
; Get pointer to next node.
putc 'c' ;->first node
putc 'd' ;->second node
mov esi,(ListNode PTR [esi]).NextPtr
;references a struct using [esi]
jmp NextNode
quit:
exit
main ENDP
END main
答案 0 :(得分:2)
有人可以解释
(ListNode PTR [esi]).NextPtr
吗?这是什么意思?
这意味着指向ListNode
寄存器中ESI
结构的开头的指针。它取消引用该指针,并计算到NextPtr
字段。
基本上就像你在C中有以下内容:
ListNode* esi;
...
return esi->NextPtr;
不,老实说,我做不到。嗯,对不起,这结果是一个非常糟糕的答案。 : - )有人可以解释
< Counter, ($ + Counter * SIZEOF ListNode) >
吗?它是如何工作的,它意味着什么?
但我可以告诉你我怎么想的。首先,我去the documentation for MASM,看看我是否能发现任何看似相关的东西。我会发现(或者,实际上,我已经知道)$
表示the current value of the location counter,而SIZEOF
是an operator that returns the number of bytes in the specified type。
所以这个gobbledygook看起来像是将Counter
的值乘以ListNode
结构的大小,然后添加位置计数器的当前值。
但我仍然不知道尖括号是什么意思。所以我尝试了Google搜索,比如“尖括号MASM”。我得到this question,这不是很有用,因为它没有答案。在MASM32帮助文件中,我看到:
视为单个文字字符串。尖括号通常用于宏调用,并使用FOR指令确保参数列表中的值被视为单个参数。 。 。每次将参数插入宏扩展时,汇编器都会删除一组尖括号。
但这对我来说也没有太大的帮助。
从哪里开始?好吧,假设代码工作,我会组装它并要求MASM生成一个列表文件(/Fl
)。然后我会检查这个列表文件,看看它实际上对生成的代码产生了什么影响。
更新:我的奉献得到了回报,我遇到了an old manual for MASM 6.1 online。我无法在微软的在线文档中找到这个,但是在本手册中,它清楚地说明了这一点。 98:
定义结构和联合变量
声明结构或联合类型后,您可以定义该类型的变量。对于定义的每个变量,内存以当前段以类型声明的格式分配。定义结构或联合变量的语法是:
[[name]] typename < [[initializer [[,initializer]]...]] > [[name]] typename { [[initializer [[,initializer]]...]] } [[name]] typename constant DUP ({ [[initializer [[,initializer]]...]] })
名称是分配给变量的标签。如果未提供名称,汇编程序将为变量分配空间,但不为其指定符号名称。 typename是先前声明的结构或联合类型的名称。
您可以为每个字段提供初始值设定项。每个初始化程序必须在类型上与类型声明中定义的字段对应。对于联合,初始化程序的类型必须与第一个字段的类型相同。初始化列表也可以使用
DUP
运算符。
所以看起来它声明了一个类型为ListNode
的未命名变量,括号中的东西是ListNode
结构的初始值设定项,有点像C代码:
struct ListNode { ... } = { Counter, ($ + Counter * sizeof(ListNode)) };
这符合对解释性评论的微弱尝试:
; struct variables Counter, and ($+Counter*SIZEOF ListNode) being declared
因为它正在使用这些值初始化ListNode
结构的前两个字段NodeData
和NextPtr
。