TASM 8086(16位)如何获取数组大小?遇SIZE运算符及地址相减错误
解决TASM中获取数组大小的问题
首先,我们来拆解你遇到的两个核心问题,然后给出可行的解决方案:
问题1:SIZE ARR返回1的原因
你用ARRAY EQU 10H,20H,30H,40H然后ARR DB ARRAY的写法存在语法误区:
- TASM里的
EQU伪指令仅支持定义单个表达式,逗号分隔的写法不会被识别为数组元素列表,反而会导致汇编器解析异常,最终ARR DB ARRAY实际上只被处理成了DB 10H(仅取第一个值),所以SIZE ARR返回1(单个字节的大小)。 - 正确的做法是用尖括号
<>把数组元素括起来,让EQU把它当成可展开的元素列表,比如:ARRAY EQU <10H,20H,30H,40H>,这样ARR DB ARRAY才会正确展开为4个字节的数组。
问题2:ADD DI,$-ARR报错的原因
错误提示Can't subtract dissimilar relative quantities的本质是跨段地址运算不被允许:
$代表当前代码段(CODE)的偏移地址,而ARR属于数据段(DATA)的符号,两个不同段的相对地址无法直接相减——汇编器无法确定它们的段基址关系,因此禁止这种操作。
可行的解决方案
方案1:用宏自动定义数组并记录大小
这种方法适合需要复用数组定义的场景,能自动生成数组和对应的大小符号:
; 定义宏,同时生成数组和对应的大小符号 ARRAY_WITH_SIZE MACRO name, elements name DB elements &name&_SIZE EQU $ - name ; 用&拼接符号名,生成比如ARR_SIZE ENDM ASSUME CS:CODE,DS:DATA CODE SEGMENT START: ; 初始化数据段 MOV AX,DATA MOV DS,AX ; 获取数组大小到CX寄存器 MOV CX,ARR_SIZE ; 这里可以遍历数组,比如用LOOP指令实现循环操作 ; 程序退出 MOV AH,4CH INT 21H CODE ENDS DATA SEGMENT ; 调用宏定义数组,自动生成ARR_SIZE ARRAY_WITH_SIZE ARR, <10H,20H,30H,40H> DATA ENDS END START
方案2:手动在数据段定义数组和大小
如果不需要复用数组定义,直接在数据段内计算大小是最简单的方式:
ASSUME CS:CODE,DS:DATA CODE SEGMENT START: MOV AX,DATA MOV DS,AX ; 直接引用预定义的数组大小 MOV CX,ARR_SIZE ; 后续数组操作... MOV AH,4CH INT 21H CODE ENDS DATA SEGMENT ; 定义数组 ARR DB 10H,20H,30H,40H ; 在同一段内用$ - ARR计算大小($是当前DATA段的偏移) ARR_SIZE EQU $ - ARR DATA ENDS END START
方案3:修正EQU写法并获取大小
如果你坚持要用EQU定义元素列表,记得用尖括号包裹元素序列:
ASSUME CS:CODE,DS:DATA ; 用尖括号把元素列表括起来,让EQU正确识别为可展开的序列 ARRAY_ELEMENTS EQU <10H,20H,30H,40H> CODE SEGMENT START: MOV AX,DATA MOV DS,AX MOV CX,ARR_SIZE ; 数组操作... MOV AH,4CH INT 21H CODE ENDS DATA SEGMENT ARR DB ARRAY_ELEMENTS ARR_SIZE EQU $ - ARR DATA ENDS END START
这些方案都能在DOSBox 0.74 + TASM 3.0下正常汇编运行,核心思路是确保数组大小的计算在同一个段内完成,避免跨段的地址运算,同时正确定义数组元素序列。
内容的提问来源于stack exchange,提问作者Nephew of Stackoverflow
相关产品推荐
相关产品推荐

