C/C++汇编的接口设计

Author: 黄建华 Date: 2000年 第8期

  C/C++功能强大,产生的代码效率高,是目前最流行的编程语言之一。但是效率最高的语言不是C/C++,而是汇编语言。只不过C/C++比起汇编语言来易移植,容易学习;汇编语言比C/C++功能更强大,冗余更少。因此,许多软件可以兼顾二者的优点,用C/C++和汇编语言混合编程。混合编程主要要解决的问题是二者的接口和参数传递,参数传递包括值传递、指针传递、引用传递等。下面以Borland C 3.1简单介绍一下值传递时的接口。
  例程用C语言编写主程序,汇编语言编写子程序,主程序中要声明子程序的原型。主程序CMAIN.CPP如下:
  //主程序cmain.cpp
  #include <stdio.h>
  extern ″C″ int addition(int x,int y);
  //此处声明子程序的原型,C必须大写,最后有分号。
  void main()
  { int x=120,y=15,z;
  z=addition(x,y);
  printf(″x,y,z:%d,%d,%d″,x,y,z);}
  Borland C 3.1中带有用于80X86的汇编工具TASM。汇编语言中须说明为何种语言调用,调用的参数以及类型。主程序调用子程序时,从后往前向堆栈中压入参数,然后是主程序的返回地址(80X86中堆栈向低地址方向生长)。前面的主程序调用子程序时堆栈情况如^08020401a^所示:
  当从堆栈中取有关参数时要用到寄存器BP,因此还须要保存BP;如果子程序中有自己的数据段,也要保存原有的DS。返回的结果如果是短整数,请放在AX中;长整数放在DX∶AX中。子程序ADDITION.ASM如下:
  ;子程序addition.asm
  .model small,c ;声明此为C/C++的子程序。
  .486   ;可以使用486的指令,包括387。
  public addition  ;addition公用,可为其它程序远调用。
  .code  ;代码段开始。
  addition proc c x:word,y:word ;addition子程序的格式。
  push bp  ;保存BP,
  mov bp,sp ;把SP值传给BP。
  mov ax,[bp+6] ;取出X。
  mov bx,[bp+8] ;取出Y。
  add ax,bx ;(AX)←X+Y。
  pop bp  ;恢复BP。
  ret  ;返回主程序。
  addition endp
  end
  现在主程序和子程序都已经完成,下面可以用Borland C 3.1来编译和连接了。
  首先,进入C主程序,选择“Options/Linker/Libraries”,在Libraries对话框中,选择“Turbo Vision”,以保证与tv.lib连接。
  其次,新建或打开ADDITION.ASM,确认无误后选择“≡/Turbo As-sembler”,汇编成功后,选择“File/Dos Shell”,在DOS提示符下键入:
  tlib tv.lib +addition.obj
  如果以后ADDITION.ASM修改了,相应ADDITION.OBJ也改变了,只需键入:
  tlib tv.lib -+addition.obj
  现在,键入exit回到Borland C 3.1环境。
  接着,新建或打开cmain.cpp,选中“Compile/Compile”,对cmain.cpp编译;选中“Compile/Link”,进行连接。
  至此,一个名为cmain.exe的可执文件产生了。
  下面,将浮点数的调用和返回加以介绍。
  C/C++中,浮点数有两种:float,占四字节;doble,占八字节。浮点参数调进汇编语言时,仍然压入堆栈,可以用上面的方法找到参数;值返回时,只需把结果保留在80X87的TOS中即可。其余与上相同。例程如下:
  //主程序fmain.cpp
  #include <stdio.h>
  extern ″C″ double fsqr(double x);
  void main()
  {double x,y;
  printf(″Enter x:″);
  scanf(″%e″,&x);
  y=fsqrt(x);
  printf(″\nx=%e\ny=%e\n″,x,y);}
  ;子程序fsqr.asm
  .model small,c
  . 486
  public fsqrt
  .code
  fsqr proc c x:qword  ;X为double型,占8字节。
  push bp
  mov bp,sp
  finit  ;协处理器初始化。
  fld qword ptr [bp+6]  ;载入X至TOS。
  fsqrt  ;TOS开方,结果仍在TOS内。
  fwait  ;与主处理器同步。
  pop bp
  ret
  fsqr exdp
  end