C# 键入marshalling从C调用fortran子例程#
我正在尝试使用p/invoke从C#代码调用FORTRAN77子例程——如果您感兴趣,我正在尝试包装ARPACK库()提供的一些功能。我有两个问题C# 键入marshalling从C调用fortran子例程#,c#,fortran,marshalling,C#,Fortran,Marshalling,我正在尝试使用p/invoke从C#代码调用FORTRAN77子例程——如果您感兴趣,我正在尝试包装ARPACK库()提供的一些功能。我有两个问题 首先,在这个上下文中,我找不到关于类型编组的清晰说明。更具体地说,以下是在我的FORTRAN子程序中声明的类型: subroutine getEigenVectors & ( Matrix, n, which, nev, ncv, maxn, maxnev, maxncv, ldv, v, d) c
首先,在这个上下文中,我找不到关于类型编组的清晰说明。更具体地说,以下是在我的FORTRAN子程序中声明的类型:
subroutine getEigenVectors
& ( Matrix, n, which, nev, ncv, maxn, maxnev, maxncv, ldv, v, d)
c %------------------%
c | Scalar Arguments |
c %------------------%
character which*2
integer n, nev, maxn, maxnev, maxncv, ldv
c %-----------------%
c | Array Arguments |
c %-----------------%
c
Real
& Matrix(n,n), v(ldv,maxncv), d(maxncv,2)
我在这里找到了一些有价值的信息:
,从中我暗示(我可能错了)我应该使用:
传递整数[marshallas(UnmanagedType.I4)]int
以传入字符串[marshallas(UnmanagedType.LPArray)]字节[]
Real
数组有人对此有什么想法吗?
第二,我不知道我是否应该把我的论点作为参考。我对FORTRAN一点也不熟悉——我知道,这使任务有点困难;然而,只有ARPACK做了我想做的事情。我确实在某个地方读到过,尽管FORTRAN子程序默认将所有参数作为引用因此,我是否应该将所有参数作为引用传递? 提前感谢您的帮助! 纪尧姆
编辑(8/6/11) 这是我最后的结论:
[DllImport("Arpack.dll", EntryPoint = "#140")]
private static extern void getEigenVectors(
[MarshalAs(UnmanagedType.LPArray)] ref float[,] matrix,
[MarshalAs(UnmanagedType.I4)] ref int n,
[MarshalAs(UnmanagedType.LPArray)] ref byte[] which,
[MarshalAs(UnmanagedType.I4)] int whichLength,
[MarshalAs(UnmanagedType.I4)] ref int nev,
[MarshalAs(UnmanagedType.I4)] ref int ncv,
[MarshalAs(UnmanagedType.I4)] ref int maxn,
[MarshalAs(UnmanagedType.I4)] ref int maxnev,
[MarshalAs(UnmanagedType.I4)] ref int maxncv,
[MarshalAs(UnmanagedType.I4)] ref int ldv,
[MarshalAs(UnmanagedType.LPArray)] ref float[,] v,
[MarshalAs(UnmanagedType.LPArray)] ref float[,] d
);
我在这里做了几件事:
- 通过将
对象编组为int
以匹配FORTRANUnmanagedType.I4
对象integer
- 传递大小为(m,n)的对象,并将其编组为
以匹配FORTRANUnmanagedType.LPArray
对象Real(n,m)
- 通过将获取的对象编组为
以匹配FORTRAN非托管类型.LPArray
对象。字符*n
对象的计算如下:字节[]
System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding(); byte[] which = encoding.GetBytes(myString);
- 按值传递
对象,并将其编组为int
以指示字符串的长度。请注意,我试图将该参数放在字符串后面以及参数列表的末尾UnmanagedType.I4
通过引用传递每个参数。我建议您从一些小测试代码开始。编译一个FORTRAN.dll,其中包含一些带有简单参数的子程序,并使用C#来实现调用。此外,您可能希望将带有多个参数的Fortran封装到单个结构中(
TYPE
keyword),这使得互操作变得更加容易
下面是一个工作示例,您可以使用它来了解它的工作原理
原始FORTRAN代码:
SUBROUTINE CALC2(BLKL,BLKW, N_LAMINA,N_SLICE, LOAD, SLOP,SKW, &
DIA1,DIA2, Y1, Y2, N1, N2, DROP1, DROP2, &
PARRAY, P_MAX, P_MAX_INDEX, ENDEFCT)
!DEC$ ATTRIBUTES DLLEXPORT :: CALC2
!DEC$ ATTRIBUTES ALIAS:'CALC2' :: CALC2
!DEC$ ATTRIBUTES VALUE :: BLKL, BLKW, N_LAMINA, N_SLICE, LOAD, SLOP, SKW
!DEC$ ATTRIBUTES VALUE :: DIA1, DIA2, Y1, Y2, N1, N2
IMPLICIT NONE
INTEGER*4, INTENT(IN) ::N_LAMINA, N_SLICE
REAL*4, INTENT(IN) :: BLKL, BLKW, LOAD, SLOP, SKW, &
DIA1, DIA2, Y1, Y2, N1, N2, &
DROP1(MAX_LAMINA), DROP2(MAX_LAMINA)
REAL*4, INTENT(OUT):: PARRAY(MAX_PATCH), P_MAX
INTEGER*4, INTENT(OUT) :: P_MAX_INDEX, ENDEFCT
INTEGER*4 :: NDIAG, N_PATCH
REAL*4 :: SLNG, SWID
REAL*4 :: DROPS_1(MAX_LAMINA), DROPS_2(MAX_LAMINA)
...
END SUBROUTINE CALC2
具有实数和整数形式的各种标量和数组值。例如,DROP1
是输入1D数组<代码>阵列将二维阵列输出为一维阵列<代码>BLKL是输入浮动
注意!DEC$ATTRIBUTES值
装饰,以避免将所有内容声明为ref
在C#中,代码由
[DllImport("mathlib.dll")]
static extern void CALC2(float major_dim, float minor_dim,
int N_lamina, int N_slices, float total_load,
float slope, float skew, float diameter_1, float diameter_2,
float youngs_1, float youngs_2, float nu_1, float nu_2,
float[] drops_1, float[] drops_2, float[] pressures,
ref float p_max, ref int p_max_index, ref EndEffect end_effect);
...
{
float max_pressure = 0;
int max_pressure_index = 0;
float[] pressures = new float[Definition.MAX_PATCH];
EndEffect end_effect = EndEffect.NO;
CALC2(length, width, lamina_count, slice_count, load, slope, skew,
dia_1, dia_2, y_1, y_2, n_1, n_2, drops_1, drops_2, pressures,
ref max_pressure, ref max_pressure_index, ref end_effect);
}
注意我没有传递任何字符串。ARPACK真是太棒了。我对fortran 77代码所做的是通过f2c-a运行它,使其成为C代码,然后构建它。如果您熟悉C,那么您可能会发现这更简单。请注意,Fortran会在每个字符串中传递一个长度变量。根据编译器和编译器选项的不同,它可以在字符串后立即传递,也可以在末尾传递。例如,我认为不需要marshalas属性,int默认为I4。你的矩阵肯定不会像那样正确排列。您需要在调试器中运行arpack代码,并查看参数是如何到达的。为什么要这样使用utf8?ht。您需要在调试器中运行arpack代码,并查看参数是如何到达的。为什么要使用utf8?根据我的经验,使用
marshallas()
过度指定参数越多,我看到的故障就越多。仅添加绝对必要的属性。例如,float
自动封送为REAL
。另请参见编译器是否有!DEC$ATTRIBUTE VALUE
规范减少C中ref
参数的数量#不能将多维数组作为float[,]
传递。另外,数组已经是引用,不需要ref
。fortranREAL::A(2,2)
作为带有4个元素的float A[]
传递。按顺序排列,它们是A11A21
A12
A22
,因为FORTRAN与C在元素顺序上不同。FORTRAN矩阵也很重要,别忘了!“所以把它作为一个浮点数进行封送。你可以测试这个浮点数,或者是一个双浮点数。”引导Raymond Chen,现在,我们是吗?结束你们当时所说的,似乎我应该传递float[,]
或double[,]
元素,而不忘记转置原始数组。我会试试看,让你知道事情的进展。不要通过数组