VC++调用Fortran子程序VC++友好的界面制作和VisualFortran强大的计算和数据处理功能,两者结合可开发行程界面友好、操作直观方便、功能强大的应用程序。如何进行VC++调用VisualFortran子程序模块,就成了需要解决的问题。1、VC++调用FORTRAN子程序的方式(1)同一工程包含VC++和Fortran语言文件对同一版本集成后的编译器可以根据不同的扩展名选择编译方式,生成目标代码文件.OBJ,然后按照指定的调用方式进行链接,生成可执行文件.EXE。(2)VC++工程文件引用Fortran语言生成的.OBJ或.LIB文件对不同版本的编译器安装集成后,VS不会自动根据文件扩展名选择编译方式,这时需用不同的工程文件。首先对VisualFortran建一工程文件,生成.OBJ文件或.LIB文件,然后在VC++工程中按照指定的调用方式进行调用,编译链接,生成可执行文件.EXE。(3)VC++工程文件调用Fortran语言生成的.DLL将已有的Fortran程序生成dll模块,有利于移植和修改,可提高效率,这样即使原dll模块中的算法做过修改,只要保证函数或子例行程序名字和入口参数不变,主调用过程无须进行重新修改或者编译。2、VC++中的声明在C++语言中调用Fortran的函数或模块,必须在C++语言的函数名前面冠以_stdcall或_cdecl关键字申明调用方式,以便编译器按照约定方式进行正确的参数传递,包括参数传递顺序、参数传递方式、堆栈处理和命名修饰等问题。C++语言调用Fortran模块的声明:extern“C”{void_stdcallSUBROUTINE(形式参数1,floatTC[],floatPC,……);float_stdcallFUNCTION(形式参数1,floatTC[],floatPC,……);}或extern“C”{void_cdeclSUBROUTINE(形式参数1,floatTC[],float*PC,……);float_cdeclFUNCTION(形式参数1,floatTC[],float*PC,……);}其中TC为数组变量。_stdcall是Pascal程序的缺省调用方式,参数采用从右到左的压栈方式,被调函数自身在返回前清空堆栈。按C/C++编译方式,_stdcall调用约定在输出函数名前面加下划线,后面加“@”符号和参数的字节数。_cdecl是C/C++的缺省调用方式,参数采用从右到左的压栈方式,传送参数的内存栈由调用者维护,每一个调用它的函数都包含清空堆栈的代码,所以产生的可执行文件大小会比调用_stdcall函数的大。由于_cdecl调用方式的参数内存栈由调用者维护,所以变长参数的函数能(也只能)使用这种调用约定。两者的优缺点还表现在:如果函数使用了_cdecl,那么栈的清除工作是由调用者完成,这样带来了一个问题,即由于不同的编译器处理栈的方式不尽相同,那么调用者能否正常完成栈的清除工作就成问题。因此_cedcl约定的函数只能被C/C++安全的调用。但如果只是VC++/Fortran的混合编程,则用_cdecl约定较方便,特别是在开发/调试初期参数个数还不能确定的情形下,开发者不用每次在参数变动后,计算参数的总字节数。__stdcall类型是WINDOWSAPI函数缺省的调用方式,由于被调函数自身在返回前清空堆栈,_cdecl存在的栈清除问题就不存在了,所以,在跨开发平台的调用中,都使用__stdcall约定。但是对可变参数函数,则必须用_cdecl约定。笔者在实际中使用的_cdecl约定例子在VisualFortran中SUBROUTINEFsub1(P,LEVM,CAPE,PLFC)!DEC$attributesC::Fsub1!DEC$attributesc,Alias:'_Fsub1'::Fsub1!DEC$attributesreference::CAPE,PLFCREALP(LEVM),CAPE,PLFC……CALLFsub2(P,LEVM,CAPE)……ENDSUBROUTINEFsub2(PP,LM,DCAPE)REALPP(LM),DCAPE……DCAPE=……END在VC++中externC{void_cdeclFsub1(floatTC[],intLEVM,float*CAPE,float*PLFC,);};intidatMax;floatPC[500],CAPE,PLFC;idatMax=500;……Fsub1(PC,idatMax,,&CAPE,&PLFC);在VC++工程中须包含libifcoremt.lib等FORTRAN基本库,或在工程中指明FORTRAN基本库的路径。3、Fortran程序制作dll模块先建立一个空的VisualFortrandll项目,在生成的文件中可以看到用cDEC$ATTRIBUTESDLLEXPORT指令声明的函数,这个函数即为该dll输出的子程序,用户可以在外部程序中调用它来完成一定的功能。可以在一个dll文件中添加cDEC$ATTRIBUTESDLLEXPORT指令声明多个函数、过程或要输出的数据。例如,!在dll中声明输出函数FactINTEGERFUNCTIONFACT(N)!DEC$ATTRIBUTESDLLEXPORT::FACTINTEGERN……END4、VC++中调用IMSL数学库函数方法一:通过调用Fortran子程序,利用Fortran子程序加入编译指令USENUMERICAL_LIBRARIES来包含确切的头文件和库,从而间接使用IMSL数学库中的函数。例如REALFUNCTIONFsub5(N)!DEC$ATTRIBUTESDLLEXPORT::Fsub5!DEC$attributesvalue::NUSEGQRUL_INT!调用IMSL中的高斯型数值积分函数INTEGERN,IREALW(N),X(N),XFIX(2)CALLGQRUL(N,X,W,1,0,0,0,XFIX)Fsub5=0.0DOI=1,50Fsub5=Fsub5+W(I)*X(I)**8ENDDORETURNEND方法二:在VC++中直接调用IMSL库函数在控制台(console)应用程序中调用IMSL库函数,必须包含dfor.lib、dfconsol.lib两个Fortran链接库,在MFC应用程序中调用IMSL库函数,则必须包含dformd.lib。如果要调用Fortran提供的数学库,须包含Imsl.lib(IMSL静态库)、Imsls_err.lib(IMSL错误处理库)、Imslmpistub.lib(基于多CPU的并行处理库)等三个基本库。