您好,欢迎访问三七文档
当前位置:首页 > 电子/通信 > 综合/其它 > C与Fortran混合编程-本地调用Fortran动态链接库
C#与Fortran混合编程-本地调用Fortran动态链接库Fortran是一门古老的语言,它是世界上最早出现的计算机高级程序设计语言,广泛应用于科学和工程计算领域。FORTRAN语言以其特有的功能在数值、科学和工程计算领域发挥着重要作用。然而Fortran程序本身不适合开发独立的应用程序,例如我们传统的桌面应用或者Web应用。因此这里我们便想将C#与Fortran结合,C#借助Fortran可以实现精度更高,计算更快的程序,而Fortran通过C#,便也能够达到可视化设计。一、基本思路运用Fortran,编写动态链接库(DLL),在DLL中提供计算的函数接口,然后在C#中调用该DLL中计算部分的函数,实现计算过程。这里需要注意的是,由于我们使用的是Fortran编译器,生成的DLL属于第三方非托管DLL,因此无法直接在程序中添加DLL的引用。具体的做法将在后续部分说明。二、编写Fortran程序,生成动态链接库文件知道思路之后便开始正式的Coding。首先新建一个空的FortranDynamic-linkLibrary项目。在Intel(R)VisualFortran点击Library,选中右图的Dynamic-linkLibrary.然后点击OK.这时的项目如下所示:点击SourcesFile文件夹,选择新建项。添加一个新的Fortran文件然后便开始Fortran代码的编写工作。这里我们主要实现两个方法:一个方法是求两个数相加之和,并返回结果。另一个是输入一个数组,对这个数组进行排序,并找出最大值,最后返回排序后的结果,并返回最大值。这里我们分别演示的是Fortran传出一个数和一个数组有何不同。关于Fortran的基本语法不是本文的讨论范畴,请读者自行查阅资料。下面给出的上述我们要实现的功能的具体Fortran代码:DOUBLEPRECISIONFUNCTIONADD(A,B)!DEC$ATTRIBUTESDLLEXPORT::ADD!DEC$ATTRIBUTESSTDCALL,ALIAS:'Add'::ADDDOUBLEPRECISION::A,BADD=A+BENDFUNCTIONSORTANDFINDMAX(ARRAY,LENGTH)!DEC$ATTRIBUTESDLLEXPORT::SORTANDFINDMAX!DEC$ATTRIBUTESSTDCALL,ALIAS:'Sortandfindmax'::SORTANDFINDMAXDOUBLEPRECISION::ARRAY(LENGTH)INTEGER::I,JDOUBLEPRECISION::SORTANDFINDMAX,TEMPSORTANDFINDMAX=ARRAY(1)DOI=1,LENGTH-1DOJ=I+1,LENGTHIF(ARRAY(I).GT.ARRAY(J))THENTEMP=ARRAY(I)ARRAY(I)=ARRAY(J)ARRAY(J)=TEMPSORTANDFINDMAX=ARRAY(J)ENDIFENDDOENDDOEND上面我们声明了两个Fortran函数,一个是计算两个数相加,一个是选择排序并找出最大值。之后我们点击VisualStudio的BuildSolution.开始编译成DLL。关于代码段解释:!DEC$ATTRIBUTESDLLEXPORT::ADD!DEC$ATTRIBUTESSTDCALL,ALIAS:'Add'::ADD这两句代码很关键。下面通过三个一致来简单的说一下以上代码段的意思和C#调用需要注意的问题。1.函数名一致:在Fortran编译器中默认的导出函数名全部是大写形式。而在C#中调用FortranDll时必须指定函数名一致。在Fortran方面解决的办法是:使用ALIAS(别名)属性指定导出函数名。例如对于下面的Fortran函数:DOUBLEPRECISIONFUNCTIONADD(A,B)!DEC$ATTRIBUTESDLLEXPORT::ADDDOUBLEPRECISIONA,BADD=A+BEND对应的C#声明为:[DllImport(MathDll)]privatestaticexterndoubleADD(doubleA,doubleB);使用ALIAS修改后的定义如下:DoublePrecisionFunctionADD(A,B)!DEC$ATTRIBUTESDLLEXPORT::ADD!DEC$ATTRIBUTESALIAS:'Add'::AddDoublePrecisionA,BAdd=A+BEnd对应的C#声明为:[DllImport(MathDll)]privatestaticexterndoubleAdd(doubleA,doubleB);而在C#中提供的解决方案是:通过使用Dlllmport的EntryPoint属性指定导出的Fortran函数名。例如:DoublePrecisionFunctionADD(A,B)!DEC$ATTRIBUTESDLLEXPORT::ADDDOUBLEPRECISIONA,BADD=A+BEND对应的C#声明为:[DllImport(MathDll,EntryPoint=ADD)]privatestaticexterndoublePlus(doubleA,doubleB);此外,还可以使用.NETFramework提供的dumpbin.exe工具查看DLL导出的函数名称。A.在开始菜单中打开MicrosoftVisualStudio2010/VisualStudioTools/VisualStudio2010命令提示。B.在命令提示窗体中将路径指向编译生成.dll文件的路径,然后输入以下命令:dumpbin/exportsFileName.dll即可查看当前目录下FileName.dIl中导出的所有函数信息。2.堆栈管理一致堆栈管理约定包括:在调用过程中子例程接受参数的数目和顺序,调用完成后由哪一方来清理堆栈等。C#语言在windows平台上的调用模式默认为StdCall模式,既由被调用方清理堆栈。而Fortran语言则默认由调用方清除。因此必须统一调用双方的堆栈清除方式才能保证2种语言间的正常函数调用。这一约定在Fortran语言或C#语言中均可以采取措施进行统一。在Fortran语言中可以通过编译指令“!DEC$”后的可选项“C”或“STDCALL”参数来实现:A.!DEC$ATTRIBUTESSTDCALL::Object该语句语句中的STDCALL模式指定由被调用方清除堆栈(其中“Object”为变量名或函数名)。B.!DEC$ATTRIBUTESC::Object该语句中的C模式声明由主调函数清除堆栈(但在传递数组和字符串参数时不能用此方法指定)。如果在C#语言内做改动,则需要在DllImport属性中设置CallingConvention字段的值为Cdecl(表示由调用方清理堆栈)或StdCall(表示由被调用方清理堆栈)。[DllImport(FileName.dll,CallingConvention=CallingConvention.StdCall)][DllImport(FileName.dll,CallingConvention=CallingConvention.Cdecl)]只有当Fortran程序和C#程序的堆栈管理一致时,才能保证正常的调用。3.参数类型保持一致在Fortran中常用的数据参数类型有:REAL:表示浮点数据类型,即小数,等价于C#的float,INTEGER:表示整数类型,相当于C#的int数据类型DOUBLEPRECISION:表示双精度数据类型,相当于C#的double数据类型。在C#调用FortranDLL是必须保证参数的一致性,例如在Fortran中变量定义的是REAL类型,而我们传入的是Double,那么就会出现计算错误。三、编写C#代码调用FortranDLLC#调用的Fortran的过程很简单,只需要注意上述说的几个问题即可。这里我们先新建一个控制台应用程序:然后将我们编译的Fortran项目所生成的DLL拷贝到控制台应用程序的Debug文件夹下。接着我们添加一个类:FortranMethod.cs该类用来调用FortranDLL。代码如下:usingSystem;usingSystem.Text;usingSystem.Runtime.InteropServices;namespaceMixedProgram{publicstaticclassFortranMethod{[DllImport(TestDll.dll,CallingConvention=CallingConvention.Cdecl)]publicstaticexterndoubleAdd(doublea,doubleb);[DllImport(TestDll.dll,CallingConvention=CallingConvention.Cdecl)]publicstaticexterndoubleSortandfindmax(double[]array,intlength);}}关于C#调用注意的事项在上面已说明,在此不再讨论。然后在Main函数中测试我们的FortranDLL。示例代码如下:usingSystem;usingSystem.Collections.Generic;usingSystem.Text;namespaceMixedProgram{classProgram{staticvoidMain(string[]args){Console.WriteLine(请输入两个数相加:);doublenum1=Convert.ToDouble(Console.ReadLine());doublenum2=Convert.ToDouble(Console.ReadLine());Console.WriteLine(输入的两个数是:+num1+,+num2);doublesum=FortranMethod.Add(num1,num2);Console.WriteLine(求和结果是:+sum);double[]Array={1,5,2,4,3,7,6};Console.WriteLine(初始数组:);for(inti=0;iArray.Length;i++)Console.Write(Array[i]+);doubleb=FortranMethod.Sortandfindmax(Array,Array.Length);Console.WriteLine(\n+排序后:);for(inti=0;iArray.Length;i++)Console.Write(Array[i]+);Console.WriteLine(\n+最大值为:);Console.WriteLine(b);Console.ReadKey();}}}到此为止,所以的工作已经完成,下面看一下结果:到此为止,C#与Fortran编程的小示例就已经完成了。总结:本文主要演示了如何使用C#调用Fortran的DLL来实现相关的计算工作。并主要讲了C#调用时应该注意的事项。在工程计算中如果对于精度要求较高,计算较复杂时,我们便可以考虑通过C#与Fortran的混合编程来达到所需的要求。本文是基于本地调用FortranDLL,下一篇将讲解基于Web调用FortranDLL.
本文标题:C与Fortran混合编程-本地调用Fortran动态链接库
链接地址:https://www.777doc.com/doc-2908369 .html