从屏幕位置获取一个字符并将其放入字符串中不起作用

问题描述

我有一个应该执行此操作的 getchar 函数

它应该输出什么:

33

它实际输出内容

3

这是我目前的尝试:

char db 0
charcolor db 0
pos_x_2 db 0
pos_y_2 db 0
_getchar:
  MOV [pos_x_2],DL
  MOV [pos_y_2],DH
  MOV BH,0
  MOV AH,03h
  INT 0x10
  MOV [pos_x],DL
  MOV [pos_y],DH
  MOV DL,pos_x_2
  MOV DH,pos_y_2
  MOV AH,02h
  INT 0x10
  MOV BH,08h
  INT 0x10
  MOV [char],AL
  MOV [charcolor],AH
  RET

解决方法

MOV DL,pos_x_2
MOV DH,pos_y_2

在 NASM 中,上述不会加载存储在 pos_x_2pos_y_2 变量中的值。相反,寄存器加载了这些变量地址的低字节。
您需要像在其余代码中一样使用方括号。

另外,如果你在阅读屏幕上的任何地方之前不厌其烦地保留光标的位置,你不应该在从例程返回之前恢复它吗?
请注意,您可以通过简单的 DL/DH 而不是使用基于内存的变量来保留/恢复 pushpop

; IN (dl,dh)
_getchar:
  push dx          ; On the stack is "Where we want to read from the screen"
  mov  bh,0
  mov  ah,03h     ; BIOS.GetCursor
  int  10h         ; -> CX DX
  pop  ax
  xchg ax,dx
  push ax          ; On the stack is "Where the cursor stood before"
  mov  ah,02h     ; BIOS.SetCursor
  int  10h
  mov  ah,08h     ; BIOS.ReadCharacterAndAttribute
  int  10h         ; -> AX
  mov  [char],ax  ; (*)
  pop  dx          ; Restore the cursor to where it stood before
  mov  ah,02h     ; BIOS.SetCursor
  int  10h
  ret

  ...

char db 0
charcolor db 0

(*) 因为 charcharcolor 变量在内存中相邻且顺序正确,所以您可以写入 AL 和 {{ 1}} 一次从 AH 开始。