VC与Fortran的混合编程
VC++调用Fortran子程序
VC++友好的界面制作和Visual Fortran强大的计算和数据处理功能,两者结合可开发行程界面友好、操作直观方便、功能强大的应用程序。如何进行VC++调用VisualFortran子程序模块,就成了需要解决的问题。
1、VC++调用FORTRAN子程序的方式
(1)同一工程包含语言文件
集成后的编译器可以根据不同的扩展名选择编译方式,生成目标代码文件.OBJ,然后按照指定的调用方式进行链接,生成可执行文件.EXE。语言文件不扩展名选择编译方式然后按照指定的调用方式进行链接,生成可执行文件.EXE。语言将已有程序成dll模块于移植和修改,这样即使原dll模块中的算法做过修改,只要保证函数或子例行程序名字和入口参数不变,主调用过程无须进行重新修改或者编译。在C语言中调用Fortran的函数或模块,必须在函数名前面冠以_stdcall关键字编译器参数传递顺序、参数传递方式、堆栈处理和命名修饰等问题。C++语言调用Fortran模块的声明:
extern “C” { void _stdcall SUBROUTINE(,……);
float _stdcall FUNCTION(,……); }extern “C” {
void _cdecl SUBROUTINE(,……);
float _FUNCTION(形式参数1,float TC[],……); }_stdcall是Pascal程序的缺省调用方式,参数采用从右到左的压栈方式,被调函数自身在返回前清空堆栈按C编译方式,_stdcall调用约定在输出函数名前面加下划线,后面加“@”符号和参数的字节数_cdecl是C/C++的缺省调用方式,参数采用从右到左的压栈方式,传送参数的内存栈由调用者维护每一个调用它的函数都包含清空堆栈的代码,所以产生的可执行文件大小会比调用_stdcall函数的大。由于_cdecl调用方式的参数内存栈由调用者维护,所以变长参数的函数能(也只能)使用这种调用约定。
函数使用了_cdecl,那么栈的清除工作是由调用者这样带来了一个问题,不同的编译器栈的方式不尽相同那么调用者能否正常栈的清除工作cedcl约定的函数只能被C/C++调用__stdcall类型WINDOWS API函数被调函数自身在返回前清空堆栈_cdecl存在的栈清除所以,在跨开发平台的调用中,都使用__stdcallSUBROUTINE Fsub1(P,LEVM,CAPE,PLFC)
!DEC$ attributes C::Fsub1
!DEC$ attributes c,Alias:'_Fsub1'::Fsub1
!DEC$ attributes reference::CAPE,PLFC
REAL P(LEVM),CAPE,PLFC
……
CALL Fsub2(P,LEVM,CAPE)
……
END
SUBROUTINE Fsub2(PP,LM,DCAPE)
REAL PP(LM),DCAPE
……
DCAPE=……
END
在VC++中
extern "C" { void _cdecl Fsub1 (float TC[], int LEVM, float *CAPE,float *PLFC,); } ;
int idatMax;
float PC[500],CAPE,PLFC;
idatMax=500;
……
Fsub1(PC,idatMax,, &CAPE, &PLFC);
在VC++工程中须包含libifcoremt.lib等FORTRAN基本库,或在工程中指明FORTRAN基本库的路径。
3、Fortran程序制作dll模块
先空的Visual Fortran dll项目,在生成的文件中可以看到用cDEC $ ATTRIBUTES DLLEXPORT 指令声明的函数,这个函数即为该dll输出的子程序,用户可以在外部程序中调用它来完成一定的功能。可以在一个dll文件中添加cDEC $ ATTRIBUTES DLLEXPORT指令声明多个函数、过程或要输出的数据。例如,
!在dll中声明输出函数 Fact
INTEGER FUNCTION FACT(N)
!DEC$ ATTRIBUTES DLLEXPORT::FACT
INTEGER N
……
END
4、VC++中调用IMSL数学库函数
加入编译指令USE NUMERICAL_LIBRARIES来包含确切的头文件和库,使用IMSL数学库中的函数。
REAL FUNCTION Fsub5(N)
!DEC$ ATTRIBUTES DLLEXPORT::Fsub5
!DEC$ attributes value::N
USE GQR