MASM中遍历自定义结构体指针数组并打印内容的实现问题
解决MASM中遍历DbRecord指针数组并打印内容的问题
嘿,我之前在写MASM程序处理指针数组时也踩过一模一样的坑——你大概率是没处理好指针的层级:数组里存的是DbRecord的指针,不是结构体本身,直接用LEA取偏移肯定会访问错误的内存区域。我来给你拆解问题,再给一个可运行的实现示例。
先明确核心误区
你的数组是DbRecord* array[512]类型,每个元素是指向结构体的指针。所以第一步要做的是:从数组里取出指针,再通过这个指针去访问结构体的字段,而不是直接对数组元素的偏移做操作。
第一步:确认你的DbRecord结构体定义(先假设是这样,你可以替换成自己的)
MASM里结构体的字段偏移是自动计算的,先确保定义没问题:
; 示例结构体,根据你的实际定义修改 DbRecord STRUCT userId DWORD ? ; 4字节的ID字段 userName BYTE 32 DUP(?) ; 32字节的名字 userAge BYTE ? ; 1字节的年龄 DbRecord ENDS
第二步:正确实现readArray函数
下面是结合Windows控制台API(WriteConsoleA)的完整函数,重点看指针解引用和字段访问的部分:
; 函数原型:void readArray(DbRecord** pArray, DWORD elementCount) readArray PROC USES ebx ecx edx esi, pArray: PTR PTR DbRecord, ; 传入的指针数组的地址 elementCount: DWORD LOCAL hConsole: HANDLE LOCAL bytesWritten: DWORD ; 获取标准输出句柄 INVOKE GetStdHandle, STD_OUTPUT_HANDLE mov hConsole, eax mov ecx, elementCount ; 初始化循环计数器 mov esi, pArray ; esi指向指针数组的起始位置 xor ebx, ebx ; ebx作为数组索引,从0开始 printNextRecord: cmp ecx, 0 jle printComplete ; 计数器归0就退出循环 ; 1. 取出当前数组元素:DbRecord* pCurrent = array[ebx] ; 32位下指针是4字节,所以用ebx*4计算偏移 mov eax, [esi + ebx * TYPE DWORD] ; 现在eax里是指向当前DbRecord的指针 ; --- 打印ID字段 --- ; 先把DWORD类型的ID转成ASCII字符串(用MASM32的dwtoa辅助函数,也可以自己实现) LOCAL idStr[16]: BYTE INVOKE dwtoa, [eax + DbRecord.userId], ADDR idStr INVOKE WriteConsoleA, hConsole, ADDR idStr, 16, ADDR bytesWritten, NULL ; --- 打印名字字段 --- ; 名字是字节数组,直接用指针+字段偏移访问 INVOKE WriteConsoleA, hConsole, [eax + DbRecord.userName], 32, ADDR bytesWritten, NULL ; --- 打印年龄字段 --- ; 年龄是单个字节,先转成DWORD再转字符串 LOCAL ageStr[4]: BYTE movzx edx, BYTE PTR [eax + DbRecord.userAge] ; 零扩展成DWORD INVOKE dwtoa, edx, ADDR ageStr INVOKE WriteConsoleA, hConsole, ADDR ageStr, 4, ADDR bytesWritten, NULL ; 打印换行分隔 LOCAL newline: BYTE 0Dh, 0Ah INVOKE WriteConsoleA, hConsole, ADDR newline, 2, ADDR bytesWritten, NULL ; 更新循环变量 inc ebx dec ecx jmp printNextRecord printComplete: ret readArray ENDP
为什么你之前用LEA没成功?
你可能尝试了类似LEA eax, [esi + ebx * 4 + DbRecord.userId]这样的代码——这是错误的!因为esi + ebx*4是指针的地址,不是结构体的地址,加上字段偏移后会指向完全无关的内存区域。正确的做法是先把指针加载到寄存器(比如eax),再以eax为基地址,加上字段偏移来访问结构体内容。
额外调试小技巧
- 用MASM的
OFFSET宏验证字段偏移:比如OFFSET DbRecord.userName应该等于SIZEOF DWORD(也就是4),如果你的结构体字段顺序不同,要确认这个值是否正确。 - 在调试器里盯着寄存器:比如检查
esi是否确实指向数组的起始地址,eax加载的指针是否对应正确的结构体,[eax + DbRecord.userId]是否是你预期的数值。
内容的提问来源于stack exchange,提问作者Chad Botting
相关产品推荐
相关产品推荐

