x8086汇编:如何通过参数传递的偏移量获取数组长度?
问题分析
你当前代码里的lengthof arr返回1的原因是:arr是函数接收的指针参数(本质是一个4字节的双字变量),而lengthof是汇编器在编译阶段计算的操作符,它只能作用于.data段中定义的数组变量,无法对运行时传递的指针计算数组实际长度。
可行实现方法
方法1:额外传递数组长度作为参数
这是最直接高效的方案,调用函数时将数组长度一并传入,函数直接使用该值:
INCLUDE Irvine32.inc ; 修改函数原型,添加数组长度参数 multiply proto, arr:ptr dword, arrLength:dword .data array dword 1,2,3,4,5,6,7,8,9,10 num dword 3 .code main PROC ; 调用时传入数组地址和编译时计算的长度 invoke multiply, addr array, lengthof array exit main ENDP multiply proc, arr:ptr dword, arrLength:dword mov ecx, arrLength ; 直接使用传入的长度值 mov eax, ecx call writedec ret multiply endp END main
方法2:使用哨兵值标记数组末尾
在数组最后添加一个特殊的“哨兵”值(比如0,前提是数组元素不会出现这个值),函数通过遍历数组直到遇到哨兵来统计长度:
INCLUDE Irvine32.inc multiply proto, arr:ptr dword .data ; 数组末尾添加哨兵值0 array dword 1,2,3,4,5,6,7,8,9,10, 0 num dword 3 .code main PROC invoke multiply, addr array exit main ENDP multiply proc, arr:ptr dword mov esi, arr xor ecx, ecx ; 初始化计数器为0 count_loop: mov eax, [esi] cmp eax, 0 ; 判断是否遇到哨兵 je count_done inc ecx ; 计数器加1 add esi, 4 ; 移动到下一个双字元素 jmp count_loop count_done: mov eax, ecx call writedec ret multiply endp END main
方法3:用结构体封装数组指针和长度
定义结构体将数组指针与长度打包,适合需要多次传递数组的复杂场景:
INCLUDE Irvine32.inc ; 定义数组信息结构体 ArrayStruct struct arrPtr ptr dword arrLen dword ArrayStruct ends multiply proto, arrInfo:ptr ArrayStruct .data array dword 1,2,3,4,5,6,7,8,9,10 num dword 3 ; 初始化结构体变量 myArrayInfo ArrayStruct <addr array, lengthof array> .code main PROC invoke multiply, addr myArrayInfo exit main ENDP multiply proc, arrInfo:ptr ArrayStruct mov esi, arrInfo mov ecx, [esi].ArrayStruct.arrLen ; 从结构体中读取长度 mov eax, ecx call writedec ret multiply endp END main
各方法对比
- 方法1:性能最优,实现简单,是x86汇编传递数组的标准做法,但需要调用者额外管理长度参数。
- 方法2:无需传递长度,但需要遍历数组,有一定性能开销,且受限于哨兵值不能出现在数组元素中。
- 方法3:适合复杂场景,将数组相关信息封装在一起,代码可读性更好,但需要额外定义结构体。
内容的提问来源于stack exchange,提问作者Syeda Rabia Hashmi
相关产品推荐
相关产品推荐

