ihah, ohah 和 int86 是什么?

Vip*_*pul 4 assembly dos bios turbo-c++ x86-16

我试图理解一个程序来获取箭头键。这是代码:

int getkeys( )
{
       union REGS i,o;
       while(!kbhit( ));
            i.h.ah=0;
       int86(22,&i,&o);
            return(o.h.ah);
 } 
Run Code Online (Sandbox Code Playgroud)

有人可以解释我这个代码。这是为了获得箭头键,但我没有得到这个代码。

Mic*_*tch 6

Turbo-C/C++ 的int86函数用于对 DOS 和 BIOS 服务进行系统中断调用。该REGS联盟是解决在中断上下文数据结构各个寄存器的方式。为了进行 DOS 或 BIOS 调用,您需要根据要进行的系统调用的要求在寄存器中设置值。Ralph Brown 的中断列表(RBIL) 是 DOS 和 BIOS 系统调用、它们的参数和返回值的极好来源。该涡轮-C文档定义int86是这样的:

Name            int86  - general 8086 software interrupt interface

Usage           int int86(int intr_num, union REGS *inregs,
                          union REGS *outregs);

Prototype in    dos.h

Description     Both of these functions execute an 8086 software
                interrupt specified by the argument intr_num.

                Before executing the software interrupt, both functions
                copy register values from inregs into the registers.

                In addition, int86x copies the segregs->x.ds and
                segregs->x.es values into the corresponding registers
                before executing the software interrupt. This feature
                allows programs that use far pointers, or that use a
                large data memory model, to specify which segment is
                to be used during the software interrupt.

                After the software interrupt returns, both functions
                copy the current register values to outregs, copy the
                status of the system carry flag to the x.cflag field
                in outregs, and copy the value of the 8086 flags register
                to the x.flags field in outregs.  In addition, int86x
                restores DS, and sets the segregs->es and segregs->ds
                fields to the values of the corresponding segment
                registers.

                If the carry flag is set, it indicates that an error
                occurred.

                int86x allows you to invoke an 8086 software interrupt
                that takes a value of DS different from the default data
                segment, and/or that takes an argument in ES.

                Note that inregs can point to the same structure that
                outregs points to.

Return value    int86 and int86x return the value of AX after completion
                of the software interrupt. If the carry flag is set
                (outregs->x.cflag != 0), indicating an error, these
                functions set _doserrno to the error code.
Run Code Online (Sandbox Code Playgroud)

int86获取要调用的中断号和两个REGS联合指针。第一个包含需要在进入中断处理程序时设置的值,第二个是检索中断返回的寄存器值的方法。

Turbo-C/C++ 的定义REGS看起来类似于:

struct WORDREGS {
    unsigned int    ax, bx, cx, dx, si, di, cflag, flags;
};

struct BYTEREGS {
    unsigned char   al, ah, bl, bh, cl, ch, dl, dh;
};

union   REGS    {
    struct  WORDREGS x;
    struct  BYTEREGS h;
};
Run Code Online (Sandbox Code Playgroud)

h联合的部分只是一种对 16 位寄存器AXBXCXDX的高 8 位寄存器和低 8 位寄存器进行寻址的机制,而不是通过完整的 16 位寄存器 via x。这段代码:

i.h.ah=0;
Run Code Online (Sandbox Code Playgroud)

只需将AH寄存器(AX的最高 8 位寄存器)设置为 0 即可传递到int86函数中。这段代码:

int86(22,&i,&o);
Run Code Online (Sandbox Code Playgroud)

正在调用软件中断 22 (0x16)。如果您查看 RBIL,Int 0x16/AH=x00您会发现它是 BIOS 调用:

KEYBOARD - GET KEYSTROKE
AH = 00h

Return:
AH = BIOS scan code
AL = ASCII character
Run Code Online (Sandbox Code Playgroud)

您将看到此 BIOS 调用返回AH 中按下的下一个字符的 BIOS 扫描代码,而AL是 ASCII 代码。

线路:

return(o.h.ah);
Run Code Online (Sandbox Code Playgroud)

返回按下的字符的 BIOS 扫描码 getkeys

注意:代码while(!kbhit( ));循环等待,直到检测到按键。Int 0x16/AH=0x00 调用用于检索该按键的 BIOS 扫描代码。