夏 娟, 赵 梅
(苏州科技学院 电子信息科学与技术学院, 江苏 苏州 215011)
汇编语言是一种面向机器的语言,其特点是运行速度快,占用内存空间小,并且可直接对硬件进行控制,但是汇编语言编写及调试程序相对高级语言要困难、复杂,尤其是进行数据处理及数值混合运算.但是C/C++作为高级语言,具有数据类型丰富、表达能力强、效率高、可移植性好且使用灵活方便等优点[1].因此,为了充分利用两种语言的优势,扬长避短,在软件开发过程中,常采用混合编程的方法,即两种语言彼此相互调用,进行参数传递,共享数据结构及数据信息.目前,在DSP芯片控制程序的开发及单片机程序的设计中,汇编语言与C/C++语言混合编程都是较为理想的解决方案.通常主程序及数据处理或图形显示程序采用C/C++语言编写,而中断处理函数、延时函数和硬件驱动程序等采用汇编语言编写,这样在提高了代码效率的同时又降低了程序设计的复杂度.
汇编语言和C/C++语言混合编程的方法有两种[2]:在C/C++源程序中直接插入汇编源代码,称为嵌入式汇编;在C/C++源程序中调用外部的汇编语言程序.
所谓嵌入式汇编是在C/C++源程序中,在需要的地方插入汇编指令,并在嵌入的汇编指令前加上关键字.
在C语言中内嵌汇编语言时,使用关键字_asm,格式如:_asm 〈操作码〉〈操作数〉
例如:asm mov ax,ds; asm push ds;
其中操作码是有效的8086指令及某些汇编伪指令db,dw,dd及extern.操作数可以是C语言中的常量、变量、标号和符号,而且还可以用结构体的成员作为操作数.当汇编指令中使用寄存器名时,不区分大小写,并只能使用8086的寄存器名.在C程序中内嵌汇编指令时,编译连接只能用TCC命令行,而且必须有-B选项[3].
由于Visual C++ 6.0有别于ANSI C,在Visual C++中嵌入汇编指令时,必须使用关键字_asm,具体格式如:_asm 〈操作码〉〈操作数〉和_asm {汇编指令}
在_asm所带的一组汇编指令中可以有标号,C/C++中的goto语句和汇编指令的跳转语句可以跳到汇编指令组中的标号处或指令组外的标号处.此外,_asm所带的一组汇编指令中只能调用没有重载的全局C++函数或者声明为extern “C”类型的函数.
以下是运用嵌入式汇编实现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++来实现相同次数的减法运算,通过比较两个程序的运行时间可以发现,采用嵌入式汇编编写的程序要比单纯采用C++语句的程序节省了约30%的时间.因此在一些对实时性要求较高的工业控制领域以及具有大量计算的软件开发中,采用汇编语言与C/C++语言混合编程方法可大大提高程序的运行速度.
嵌入式汇编方式虽然简单,但是主要适用于汇编语言程序较短的情况,在实际应用中,常将汇编语言程序作为C语言的一个外部子过程来调用.
汇编子程序的开头必须执行指令:push bp和mov bp,sp
这两条指令使bp成为一个指向堆栈中各元素的指针,是参数传递的关键.在这两条指令后可通过加上sub sp,space语句实现对局部数据的分配.其中space是以字节计算的局部数据区的总大小,通过sp值的减少在堆栈中为局部数据保留一个空间,而在汇编过程结束时应恢复该空间.当要访问某个参数时,可以通过参数与bp的位移量来确定.假设返回地址字节数为M,参数与bp间的参数所占的总字节数为N,那么参数与bp的位移量S等于M+N+2,在访问该参数时可用以下语句实现:mov bx,[bp+S]
退出汇编程序时,应执行以下3步:1)如果在汇编过程开始时保存了寄存器值,那么应以入栈相反的顺序一一弹出堆栈;2)如果分配了局部数据空间,应执行指令mov sp,bp及pop bp;3)用ret返回调用程序.
当调用结束后,汇编子程序的返回值是通过寄存器DX和AX传递的.当返回值的类型是简单型,而且长度不超过4字节时,返回值长度与所放的默认寄存器的关系如表1所示.当返回值超过4字节时,返回值存放在存储区中.
表1 返回值与默认寄存器的关系
调用汇编子程序必须遵循3个原则:1)命名原则.汇编过程命名时,函数名前需加下划线“_”.由于C/C++源程序在编译时,自动地在变量或函数名前加下划线,而C/C++源程序调用汇编过程时,则直接使用该过程名而不加下划线,因此函数名前必须加下划线,而且函数名不得超过8个字节;2)调用原则.在C源程序中,使用关键字extern对函数及变量名进行说明,而在C++程序中,使用extern “C”来说明函数及变量名;3)参数传递原则.参数应按其在参数表中出现顺序的相反顺序被压入堆栈,此外不同类型的参数在栈中所占的字节数也不同[4].
以下是C程序调用汇编程序的一个实例.在C程序中提示用户输入n的值,用汇编子程序求出1至n的累加和,并将该结果返回,在C程序中输出结果.
#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调用的汇编子程序过程
.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++语言与汇编语言的混合编程,是一种有效的编程方法,在提高代码效率的同时又降低了程序设计的复杂度.在实际运用中,要注意内存模式以及寄存器的分配问题,还应考虑程序的可移植性[5].因此,在具体的程序设计中,应该综合考量各种语言的优缺点,权衡利弊,只有这样才能开发出高效稳定的程序.
参考文献:
[1] 谭浩强.C程序设计[M]. 北京:清华大学出版社,2008.
[2] 刘红玲,赵梅.微机原理与接口技术实用教程[M].北京:电子工业出版社,2008.
[3] 翟乃强,隋树林.汇编语言与C语言及Visual C++混合编程[J].青岛科技大学学报:自然科学版,2003,24(9):136-138.
[4] 沈美明,温冬蝉.IBM-PC 汇编语言程序设计[M]. 北京:清华大学出版社,1994.
[5] 阿娜古丽 阿布拉.C语言与汇编语言相互调用实现混合编程[J]. 电脑编程技巧与维护,2009,3(10):46-50.