2010-01-18 48 views
7

背景:我的任務是編寫Unitech HT630的數據收集程序,該程序運行專有的DOS操作系統,可以運行爲16位MS DOS編譯的可執行文件,儘管存在一些限制。我正在使用Digital Mars C/C++編譯器,它似乎工作得很好。C中這兩種內聯彙編程序的區別是什麼?

對於一些我可以使用標準C庫的東西,但是其他的東西比如繪製在單元的屏幕上需要彙編代碼。設備文檔中給出的程序集示例與在C/C++中使用內聯彙編代碼的教程不同。作爲參考,以下示例中的​​是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, &regs, &regs); 
} 

如何我總是被告知使用內聯彙編:

/* 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

標題誤導/錯誤。第一個版本沒有內聯asm,只是系統調用的函數調用包裝器。 (或者一個編譯器可以實現'int86()'作爲一個內聯和內聯的右asm)。 – 2016-11-08 23:32:28

回答

9

當您使用int86函數調用時,這是一個C運行時庫調用,它設置寄存器併發出一個DOS int中斷函數。這兩種方法在使用內聯彙編器時都是相同的,只有編譯和鏈接時,代碼實際上嵌入到了對象代碼中。

內聯彙編將被視爲更快,因爲您沒有涉及調用C運行時庫來調用DOS中斷的開銷。在使用內聯彙編時,負責確保有足夠的堆棧空間,而C運行時庫負責在調用int86函數之前設置寄存器時分配堆棧空間。

int86是一種調用DOS中斷更容易的方法。這在舊版Borland Turbo C編譯器套件和微軟中非常受歡迎,在Win 3.1發佈之前,我正在談論舊編譯器。

說到中斷0x10的,這是負責視頻輸出,如果我沒有記錯,在當時,一些BIOS的破壞了bp寄存器和解決方法是要做到這一點:

__asm{ 
    push bp; 
} 
/* set up the registers */ 
int86(0x10, &regs, &regs); 
__asm{ 
    pop bp; 
} 

你可以瞭解Ralph Brown的中斷列表here上的各種BIOS功能。另外HelpPC v2.1也可以幫助,發現here

+0

我想我現在在大學裏有一份拉爾夫布朗的中斷名單,我不知道我在做什麼。似乎我忘記了這個可怕的資源存在,謝謝!這非常有幫助。 – 2010-01-18 16:31:12

+0

+1拉爾夫布朗的中斷列表和HelpPc – 2010-01-18 16:52:40

0

這不是內聯彙編,這是C.非常低級別的C,使用功能造成中斷,但仍然C.

This page有一些文件(對於DJGPP編譯器,你的工作方式有所不同),包括用來表示寄存器的結構。報告還指出:

需要注意的是,不同的是__dpmi_int 功能,即通過 INT86去請求類似功能 特殊加工,使它們 適用於從保護模式 程序調用實模式 中斷。例如,如果某個特定的例程在BX中需要一個指針,則int86 希望您將一個(保護模式) 指針放入EBX中。因此,int86 應該對每個 中斷和函數都有特定的支持,你調用這個 的方式。目前,它僅支持所有可用的中斷和 功能的一個子集 [...]如果你想知道,如果

+0

對於DJGPP C編譯器來說這是真的,因爲int86不是一個標準函數,它沒有給出,數字火星編譯器以相同的方式工作,它可能有或多或少的限制 – Alon 2010-01-18 15:37:50

1

第一種形式是更具可讀性這也算個什麼;-)

int86正在做一些背後的事情,只編譯你的程序並檢查生成的彙編代碼

+0

「第一種形式更具可讀性」。它是? – 2010-01-18 15:46:07

+0

我認爲哪種形式比其他形式更「可讀」是個人意見的問題,因爲我個人認爲第二種形式更具可讀性,但都可以理解。解開編譯後的代碼將是不得已而爲之的,如果有人在這裏沒有答案,我肯定會走這條路。 – 2010-01-18 15:55:17

+0

第一種形式對於內聯彙編使用不同格式的編譯器更易讀。但是你可能會擔心不必要的函數調用的開銷,再加上對REGS' union的元素的尋址,那麼大概是'int86'將所有寄存器(在union中定義的所有那些寄存器,而不僅僅是你使用的)從內存,然後將它們全部複製出來(然後丟棄)。 – 2010-01-18 16:17:50

1

通過調用int86,你的代碼保持在C.不管怎樣,它都是通過執行系統中斷來寫入像素。

如果你有像素的很多寫的,你開始認真打速度的問題,有可能是直接寫入到像素存儲器更直接(和更安全的,但可能是值得的)的方式。

+0

可能有一點我會有很多像素來編寫,因爲客戶端在應用程序啓動時正在討論啓動畫面。目前,我只需要在屏幕上繪製奇數行。到時候,這個問題可能最終成爲它自己的問題。 – 2010-01-18 16:03:07

+0

@ Heather:是的,我擡頭看着你的機器,屏幕是單色的,很小,所以我懷疑圖形是否會成爲瓶頸。 – 2010-01-18 18:44:33

1

這兩個代碼片段完成同樣的事情。第一個優點是,當你切換編譯器時,你仍然有可能使用它。並且你不會跺腳在'C'編譯器的代碼生成器用於其他目的的寄存器上。你絕對會忘記在你的asm片段中照顧一些東西。

+0

我懷疑我沒有做我需要在asm塊中做的事情。謝謝。 – 2010-01-18 16:48:21

1

您應該檢查編譯器手冊以瞭解誰負責在內聯彙編部分之後恢復寄存器值。由於您的變量被分配給寄存器,所以這些值的意外更改可能會導致難以發現的錯誤。 int86(0x10,& regs,& regs); 保存寄存器並在執行軟件中斷後恢復它們。

一些編譯器接受指令來定義一個clobber列表(應該保存和恢復的寄存器)。通常彙編程序部分應該保存寄存器和標誌,這些寄存器和標誌將通過push進行更改,並使用pop進行恢復,無論是編譯器還是您自己。因此,第一個例子應該是首選。

+0

我同意int86 - 我想我會使用這種方法是安全的,除非速度成爲一個真正的問題,謝謝:) – 2010-01-18 17:09:13

相關問題