YASM 8086读取文件字符串并按第六列排序的实现困境
解决方案:YASM 8086 实现最后10条记录按第6列排序
核心思路
8086原生浮点操作复杂度高,先把第6列的[-9.99;9.99]实数缩放为整数(乘以100),比如9.99转成999,-9.99转成-999,用整数排序替代浮点排序简化逻辑。再用冒泡排序(适合10个元素的小规模场景)对保存的行指针和缩放后的值排序,最后按排序后的顺序输出整行到新文件。
步骤1:实数转缩放整数(补全预处理逻辑)
假设你已将第6列字符串读取到缓冲区,以下是转换代码:
; 输入:DS:SI 指向第6列字符串(如 "-3.14" 或 "5.00") ; 输出:AX = 缩放后的整数(-314 或 500) convert_real_to_scaled: xor ax, ax ; 初始化结果为0 xor bx, bx mov bl, 1 ; 符号标记:1正/-1负 mov cx, 0 ; 小数位数计数器 ; 处理符号位 cmp byte [si], '-' jne .positive mov bl, -1 inc si .positive: ; 处理整数部分 .next_int_digit: cmp byte [si], '.' je .decimal_part cmp byte [si], 0 ; 假设字符串以0终止 je .end_convert sub byte [si], '0' mov dl, [si] mov dx, ax mov ax, 10 mul dx ; AX = AX * 10 add ax, dl ; AX += 当前数字 inc si jmp .next_int_digit .decimal_part: inc si .next_dec_digit: cmp cx, 2 ; 最多取两位小数 je .end_convert cmp byte [si], 0 je .pad_zero sub byte [si], '0' mov dl, [si] mov dx, ax mov ax, 10 mul dx add ax, dl inc si inc cx jmp .next_dec_digit .pad_zero: ; 不足两位小数补0 cmp cx, 2 je .end_convert mov dx, ax mov ax, 10 mul dx inc cx jmp .pad_zero .end_convert: ; 应用符号 mov dx, ax mov ax, bx mul dx ; AX = AX * 符号值 ret
步骤2:冒泡排序实现(针对10个行条目)
先定义存储行信息的结构体,再实现排序:
; 行条目结构体:存储行指针和缩放后的值 struc RowEntry .ptr resd 1 ; 行内存地址(段+偏移,32位) .scaled_val resw 1 ; 缩放后的整数值 endstruc ; 假设已初始化数组:RowEntry row_list[10] ; 对row_list按.scaled_val升序排序 sort_row_list: mov cx, 9 ; 外层循环次数:n-1 .outer_loop: mov si, 0 ; 数组起始偏移 mov bx, cx ; 内层循环次数:n-1-i .inner_loop: ; 比较相邻元素的缩放值 mov ax, [row_list + si + RowEntry.scaled_val] cmp ax, [row_list + si + RowEntry_size + RowEntry.scaled_val] jle .no_swap ; 当前值<=下一个值,不交换 ; 交换两个RowEntry的内容 ; 交换32位行指针 mov dx, [row_list + si + RowEntry.ptr] mov bp, [row_list + si + RowEntry.ptr + 2] xchg dx, [row_list + si + RowEntry_size + RowEntry.ptr] xchg bp, [row_list + si + RowEntry_size + RowEntry.ptr + 2] mov [row_list + si + RowEntry.ptr], dx mov [row_list + si + RowEntry.ptr + 2], bp ; 交换16位缩放值 xchg ax, [row_list + si + RowEntry_size + RowEntry.scaled_val] mov [row_list + si + RowEntry.scaled_val], ax .no_swap: add si, RowEntry_size dec bx jnz .inner_loop dec cx jnz .outer_loop ret
步骤3:排序后输出到新文件
假设输出文件句柄已存在于BX中:
; 遍历排序后的数组,输出每行到文件 output_sorted_rows: mov cx, 10 mov si, 0 .output_loop: ; 获取行地址:ES:DI = 行的段+偏移 mov di, [row_list + si + RowEntry.ptr] mov es, [row_list + si + RowEntry.ptr + 2] ; 查找换行符,计算行长度(假设行以0x0A结尾) mov bp, di .find_newline: cmp byte [es:bp], 0x0A je .found_newline inc bp jmp .find_newline .found_newline: sub bp, di inc bp ; 包含换行符的总长度 ; DOS写文件调用:AH=0x40 push ds mov ds, es mov dx, di mov ah, 0x40 int 0x21 pop ds add si, RowEntry_size dec cx jnz .output_loop ret
注意事项
- 若需降序排序,只需把冒泡排序中的
jle .no_swap改为jge .no_swap。 - 确保行指针存储了正确的段和偏移地址,8086内存寻址需注意分段逻辑。
- 如果你使用8087浮点协处理器,也可直接比较浮点值,但缩放整数的方法更适配无协处理器环境,代码更简洁。
内容的提问来源于stack exchange,提问作者gailtye
相关产品推荐
相关产品推荐

