背景:我的任务是编写一个Unitech HT630的数据收集程序,它运行一个专有的DOS操作系统,可以运行为16位MS DOS编译的可执行文件,虽然有一些限制。我正在使用Digital Mars C / C ++编译器,它似乎运行得很好。
对于某些我可以使用标准C库的东西,但是在单元的屏幕上绘制等其他东西需要汇编代码。设备文档中给出的汇编示例与我在C / C ++中使用内联汇编代码的方式不同。作为参考,以下示例中的BYTE
类型为unsigned char
。
我给出的示例代码示例:
#include <dos.h>
/* Set the state of a pixel */
void LCD_setpixel(BYTE x, BYTE y, BYTE status) {
if(status > 1 || x > 63 || y > 127) {
/* out of range, return */
return;
}
/* good data, set the pixel */
union REGS regs;
regs.h.ah = 0x41;
regs.h.al = status;
regs.h.dh = x;
regs.h.dl = y;
int86(0x10, ®s, ®s);
}
我如何被教导使用内联汇编:
/* Set the state of a pixel */
void LCD_setpixel(BYTE x, BYTE y, BYTE status) {
if(status > 1 || x > 63 || y > 127) {
/* out of range, return */
return;
}
/* good data, set the pixel */
asm {
mov AH, 41H
mov AL, status
mov DH, x
mov DL, y
int 10H
}
}
两种形式似乎都有效,到目前为止我还没有遇到任何一种方法的问题。对于DOS编程,一种形式被认为比另一种更好吗? int86
函数是否为我处理了一些事情,我在第二个示例中没有使用自己的汇编代码处理自己?
提前感谢您的帮助。
答案 0 :(得分:9)
当您使用int86
函数调用时,这是一个C运行时库调用,用于设置寄存器并发出DOS int
错误函数。两种方法都是相同的,只有一个例外,当你使用内联汇编程序时,代码实际上是在编译和链接时嵌入到目标代码中。
内联汇编会被认为更快,因为您没有调用C运行时库为您调用DOS中断所涉及的开销。在使用内联汇编时,有责任确保有足够的堆栈空间,而C Runtime库在调用int86
函数之前设置寄存器时负责分配堆栈空间。
int86
是一种让调用DOS中断更容易的方法。这在旧的Borland Turbo C编译器套件和微软中非常受欢迎,我在谈论Win 3.1出现之前的旧编译器。
说到负责视频输出的中断0x10,如果我没记错的话,当时有些BIOS破坏了bp
寄存器,解决方法就是这样做:
__asm{
push bp;
}
/* set up the registers */
int86(0x10, ®s, ®s);
__asm{
pop bp;
}
您可以在Ralph Brown的中断列表here上找到广泛的BIOS功能。此外,HelpPC v2.1也可以提供帮助,找到here。
答案 1 :(得分:1)
第一种形式更具可读性,也适用于某些事物; - )
如果你想知道int86是否在你背后做了什么,只需编译你的程序并检查生成的汇编代码
答案 2 :(得分:1)
通过调用int86,您的代码保留在C中。无论哪种方式,它都是通过执行系统中断来写入像素。
如果您要编写 lot 像素,并且开始严重打击速度问题,可能会有一种更直接(并且更不安全但可能有价值)的方式直接写入像素存储器中。
答案 3 :(得分:1)
两个代码段都完成了同样的事情。第一个的一大优点是,当您切换编译器时,您仍有可能仍然可以使用它。而且你没有踩到'C'编译器的代码生成器用于其他目的的寄存器。你绝对忘记在你的asm片段中处理的事情。
答案 4 :(得分:1)
您应该检查编译器手册,找出在内联汇编部分后负责恢复寄存器值的人员。由于您的变量已分配给寄存器,因此值的意外更改可能会导致难以发现的错误。 int86(0x10,&amp; regs,&amp; regs); 执行软件中断后保存寄存器并恢复它们。
某些编译器接受指令来定义一个clobber列表(应该保存和恢复的寄存器)。通常,汇编程序部分应该保存寄存器和标志,这些寄存器和标志将通过push进行更改,并使用pop通过编译器或您自己进行恢复。因此,应首选第一个例子。
答案 5 :(得分:0)
那不是内联汇编,它是C.非常低级别的C,使用一个函数来引起中断,但仍然是C。
This page有一些文档(对于DJGPP编译器,您的工作可能会有所不同),包括用于表示寄存器的结构。它还指出:
请注意,与__dpmi_int不同 功能,请求通过 int86和类似的函数是 经过特殊加工制作而成 适合调用实模式 来自保护模式的中断 程式。例如,如果特定的话 例程在BX,int86中获取指针 期望你放一个(保护模式) EBX中的指针。因此,int86 应该对每个人都有具体的支持 中断和函数你调用它 办法。目前,它只支持一个 所有可用中断的子集和 功能[...]