基本目标 : 利用c#调用 fortran中的 souroutine
或者 function
方法。通过把fortran 代码编译成 .dll
(windows)/.so
(unix) 动态库,放到 c# 的执行路径下。再通过 c# 中的DllImport
方法导入库函数,实现在 c# 中调用 fortran 方法。
1. DllImport
方法
该方法 来自 System.Runtime.InteropServices , 是由.Net提供的方法。例如可以使用下面的代码调用user32.dll
中的MessageBox
方法。
using System;
using System.Runtime.InteropServices;
MessageBox (IntPtr.Zero,"Please do not press this again.", "Attention", 0);
[DllImport("user32.dll")]
static extern int MessageBox (IntPtr hWnd, string text, string caption,
int type);
这里在c# 中声明方法的时候需要注意以下几点:
- 函数应该声明为 static, extern 方法
- 函数的参数类型需要注意,这里仅仅以fortran为例。下文介绍了几种常见参数传递的对应情况。
DllImport
方法有几个参数也需要注意:
- EntryPoint:这需要使用一些第三方工具从dll / so 文件中查找。win下使用vs 带的 dumpbin.exe方法,使用
dumpbin /EXPORTS target.dll
命令查看。linux 下使用nm -D target.so
查找定义的方法的entrypoint。 - CallingConvention: 主要使用
CallingConvention.Cdecl
或者CallingConvention.StdCall
, 具体差别可以google.
2. c# 方法 与 Fortran 方法 参数对应
这里以示例代码来说明
module one
implicit none
abstract interface
subroutine Add(b, c, a)
implicit none
integer b
real*8 a
dimension a(*)
real*8 c
end subroutine
end interface
contains
subroutine CallfuntoAdd(f, b, c, a)
!DEC$ ATTRIBUTES ALIAS:'CallfuntoAdd' :: CallfuntoAdd
!DEC$ ATTRIBUTES DLLEXPORT :: CallfuntoAdd
!DEC$ ATTRIBUTES reference :: f, a, b, c
implicit none
real*8 c
integer b
real*8 a
dimension a(*)
procedure(Add)::f
Call f(b, c, a)
write(*,*) " c = ", c
return
end subroutine
end module one
在上面的Fortran代码里定义了一个CallfuntoAdd(f, b, c, a)方法,可以通过!DEC$
被导出到 dll 文件中。这里f 是一个回调函数, b 是integer类型, c是real*8类型, a 是一个一维数组。
public class c1
{
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void AddFunc(ref int b, ref double c, [In] IntPtr a);
public static void Add1(ref int b, ref double c, [In] IntPtr a)
{
double[] a1 = new double[b];
Marshal.Copy(a, a1, 0, b);
c = 0;
for (int i = 0; i < b; i++)
{
c += a1[i];
}
}
[DllImport("mod1.dll", EntryPoint = "__one_MOD_callfuntoadd", CallingConvention = CallingConvention.Cdecl)]
public static extern void CallfuntoAdd([MarshalAs(UnmanagedType.FunctionPtr)] AddFunc f, ref int b, ref double c, double[] a);
public static void Main()
{
double c;
double[] a = new double[3] { 3.0, 2.0, 4.0 };
int b = a.Length;
c = 0;
CallfuntoAdd(Add1, ref b, ref c, a);
Console.WriteLine($" c = {c}");
}
}
上面的c# 代码定义了一个CallfuntoAdd函数用来表示 fortran中的CallfuntoAdd方法。这c# 的函数名可以通过fortran 中 !DEC$ ATTRIBUTES ALIAS:'CallfuntoAdd' :: CallfuntoAdd
重新定义。在c#中使用委托来表示fortran中的回调函数。可以看到c# 中的CallfuntoAdd函数参数与 fortran中的CallfuntoAdd 函数参数的对应关系。
fortran | c# |
---|---|
integer | ref int |
real*4 | ref float |
real*8 | ref double |
一维数值 real*8, dimension(
标签:c#,fortran,C#,double,编程,CallfuntoAdd,dll,Fortran,ref
From: https://www.cnblogs.com/hugowu-blog/p/18085641
相关文章
|