夏 娟, 趙 梅
(蘇州科技學(xué)院 電子信息科學(xué)與技術(shù)學(xué)院, 江蘇 蘇州 215011)
匯編語言是一種面向機器的語言,其特點是運行速度快,占用內(nèi)存空間小,并且可直接對硬件進行控制,但是匯編語言編寫及調(diào)試程序相對高級語言要困難、復(fù)雜,尤其是進行數(shù)據(jù)處理及數(shù)值混合運算.但是C/C++作為高級語言,具有數(shù)據(jù)類型豐富、表達能力強、效率高、可移植性好且使用靈活方便等優(yōu)點[1].因此,為了充分利用兩種語言的優(yōu)勢,揚長避短,在軟件開發(fā)過程中,常采用混合編程的方法,即兩種語言彼此相互調(diào)用,進行參數(shù)傳遞,共享數(shù)據(jù)結(jié)構(gòu)及數(shù)據(jù)信息.目前,在DSP芯片控制程序的開發(fā)及單片機程序的設(shè)計中,匯編語言與C/C++語言混合編程都是較為理想的解決方案.通常主程序及數(shù)據(jù)處理或圖形顯示程序采用C/C++語言編寫,而中斷處理函數(shù)、延時函數(shù)和硬件驅(qū)動程序等采用匯編語言編寫,這樣在提高了代碼效率的同時又降低了程序設(shè)計的復(fù)雜度.
匯編語言和C/C++語言混合編程的方法有兩種[2]:在C/C++源程序中直接插入?yún)R編源代碼,稱為嵌入式匯編;在C/C++源程序中調(diào)用外部的匯編語言程序.
所謂嵌入式匯編是在C/C++源程序中,在需要的地方插入?yún)R編指令,并在嵌入的匯編指令前加上關(guān)鍵字.
在C語言中內(nèi)嵌匯編語言時,使用關(guān)鍵字_asm,格式如:_asm 〈操作碼〉〈操作數(shù)〉
例如:asm mov ax,ds; asm push ds;
其中操作碼是有效的8086指令及某些匯編偽指令db,dw,dd及extern.操作數(shù)可以是C語言中的常量、變量、標號和符號,而且還可以用結(jié)構(gòu)體的成員作為操作數(shù).當匯編指令中使用寄存器名時,不區(qū)分大小寫,并只能使用8086的寄存器名.在C程序中內(nèi)嵌匯編指令時,編譯連接只能用TCC命令行,而且必須有-B選項[3].
由于Visual C++ 6.0有別于ANSI C,在Visual C++中嵌入?yún)R編指令時,必須使用關(guān)鍵字_asm,具體格式如:_asm 〈操作碼〉〈操作數(shù)〉和_asm {匯編指令}
在_asm所帶的一組匯編指令中可以有標號,C/C++中的goto語句和匯編指令的跳轉(zhuǎn)語句可以跳到匯編指令組中的標號處或指令組外的標號處.此外,_asm所帶的一組匯編指令中只能調(diào)用沒有重載的全局C++函數(shù)或者聲明為extern “C”類型的函數(shù).
以下是運用嵌入式匯編實現(xiàn)1億次減法運算的程序.
long s1=0,s2=0;
while(1)
{
_asm
{
mov eax,10000
lp2: mov ecx,10000
lp1: loop lp1;
dec eax
jz ext
jnz lp2
}
}
ext:
return;
在實驗中還采用了C++來實現(xiàn)相同次數(shù)的減法運算,通過比較兩個程序的運行時間可以發(fā)現(xiàn),采用嵌入式匯編編寫的程序要比單純采用C++語句的程序節(jié)省了約30%的時間.因此在一些對實時性要求較高的工業(yè)控制領(lǐng)域以及具有大量計算的軟件開發(fā)中,采用匯編語言與C/C++語言混合編程方法可大大提高程序的運行速度.
嵌入式匯編方式雖然簡單,但是主要適用于匯編語言程序較短的情況,在實際應(yīng)用中,常將匯編語言程序作為C語言的一個外部子過程來調(diào)用.
匯編子程序的開頭必須執(zhí)行指令:push bp和mov bp,sp
這兩條指令使bp成為一個指向堆棧中各元素的指針,是參數(shù)傳遞的關(guān)鍵.在這兩條指令后可通過加上sub sp,space語句實現(xiàn)對局部數(shù)據(jù)的分配.其中space是以字節(jié)計算的局部數(shù)據(jù)區(qū)的總大小,通過sp值的減少在堆棧中為局部數(shù)據(jù)保留一個空間,而在匯編過程結(jié)束時應(yīng)恢復(fù)該空間.當要訪問某個參數(shù)時,可以通過參數(shù)與bp的位移量來確定.假設(shè)返回地址字節(jié)數(shù)為M,參數(shù)與bp間的參數(shù)所占的總字節(jié)數(shù)為N,那么參數(shù)與bp的位移量S等于M+N+2,在訪問該參數(shù)時可用以下語句實現(xiàn):mov bx,[bp+S]
退出匯編程序時,應(yīng)執(zhí)行以下3步:1)如果在匯編過程開始時保存了寄存器值,那么應(yīng)以入棧相反的順序一一彈出堆棧;2)如果分配了局部數(shù)據(jù)空間,應(yīng)執(zhí)行指令mov sp,bp及pop bp;3)用ret返回調(diào)用程序.
當調(diào)用結(jié)束后,匯編子程序的返回值是通過寄存器DX和AX傳遞的.當返回值的類型是簡單型,而且長度不超過4字節(jié)時,返回值長度與所放的默認寄存器的關(guān)系如表1所示.當返回值超過4字節(jié)時,返回值存放在存儲區(qū)中.
表1 返回值與默認寄存器的關(guān)系
調(diào)用匯編子程序必須遵循3個原則:1)命名原則.匯編過程命名時,函數(shù)名前需加下劃線“_”.由于C/C++源程序在編譯時,自動地在變量或函數(shù)名前加下劃線,而C/C++源程序調(diào)用匯編過程時,則直接使用該過程名而不加下劃線,因此函數(shù)名前必須加下劃線,而且函數(shù)名不得超過8個字節(jié);2)調(diào)用原則.在C源程序中,使用關(guān)鍵字extern對函數(shù)及變量名進行說明,而在C++程序中,使用extern “C”來說明函數(shù)及變量名;3)參數(shù)傳遞原則.參數(shù)應(yīng)按其在參數(shù)表中出現(xiàn)順序的相反順序被壓入堆棧,此外不同類型的參數(shù)在棧中所占的字節(jié)數(shù)也不同[4].
以下是C程序調(diào)用匯編程序的一個實例.在C程序中提示用戶輸入n的值,用匯編子程序求出1至n的累加和,并將該結(jié)果返回,在C程序中輸出結(jié)果.
#include
extern int sum(int x);
main ( )
{ int x;
Int y;
printf(“please input numbers: ”);
scanf(“%d”,&x);
printf(“the sum is:%d ”,sum(x));
printf(“press any key to continue: ”);
scanf(“%d”,&y);}
;供C調(diào)用的匯編子程序過程
.model small
.code
public _sum
_sum proc
push bp
mov bp,sp
mov cx,[bp+4]
xor ax,ax
mov bx,1
again: add ax,bx
inc bx
loop again
pop bp
ret
_sum endp
end
C/C++語言與匯編語言的混合編程,是一種有效的編程方法,在提高代碼效率的同時又降低了程序設(shè)計的復(fù)雜度.在實際運用中,要注意內(nèi)存模式以及寄存器的分配問題,還應(yīng)考慮程序的可移植性[5].因此,在具體的程序設(shè)計中,應(yīng)該綜合考量各種語言的優(yōu)缺點,權(quán)衡利弊,只有這樣才能開發(fā)出高效穩(wěn)定的程序.
參考文獻:
[1] 譚浩強.C程序設(shè)計[M]. 北京:清華大學(xué)出版社,2008.
[2] 劉紅玲,趙梅.微機原理與接口技術(shù)實用教程[M].北京:電子工業(yè)出版社,2008.
[3] 翟乃強,隋樹林.匯編語言與C語言及Visual C++混合編程[J].青島科技大學(xué)學(xué)報:自然科學(xué)版,2003,24(9):136-138.
[4] 沈美明,溫冬蟬.IBM-PC 匯編語言程序設(shè)計[M]. 北京:清華大學(xué)出版社,1994.
[5] 阿娜古麗 阿布拉.C語言與匯編語言相互調(diào)用實現(xiàn)混合編程[J]. 電腦編程技巧與維護,2009,3(10):46-50.