C# 从C调用FORTRAN子例程#
我想将FORTRAN DLL导入visual C#。虽然我已经用函数实现了这一点,但当我想要导入具有多个输出的子例程时,问题就出现了。下面是一个简单的例子:C# 从C调用FORTRAN子例程#,c#,fortran,pinvoke,dllimport,C#,Fortran,Pinvoke,Dllimport,我想将FORTRAN DLL导入visual C#。虽然我已经用函数实现了这一点,但当我想要导入具有多个输出的子例程时,问题就出现了。下面是一个简单的例子: FORTRAN DLL: Subroutine MySub(a,b,x,y) !DEC$ ATTRIBUTES DLLEXPORT, STDCALL, ALIAS:'MySub' :: MySub Implicit None Integer, INTENT(IN) :: a,b Integer, INTENT(OUT) :: x,y
FORTRAN DLL:
Subroutine MySub(a,b,x,y)
!DEC$ ATTRIBUTES DLLEXPORT, STDCALL, ALIAS:'MySub' :: MySub
Implicit None
Integer, INTENT(IN) :: a,b
Integer, INTENT(OUT) :: x,y
y=a+b
x=2*a+3*b
End Subroutine MySub
using System;
using System.Runtime.InteropServices;
namespace AlReTest
{
class Program
{
[DllImport(@"D:\...\AltRetTest.dll", CallingConvention=CallingConvention.StdCall)]
public static extern int MySub(int a, int b, [Out] int x, [Out] int y);
static void Main(string[] args)
{
int a = 4;
int b = 3;
int x = 0;
int y = 0;
MySub(a, b, x, y);
Console.WriteLine(x);
Console.WriteLine(y);
Console.WriteLine(MySub(a, b, x, y));
}
}
}
C#控制台应用程序:
Subroutine MySub(a,b,x,y)
!DEC$ ATTRIBUTES DLLEXPORT, STDCALL, ALIAS:'MySub' :: MySub
Implicit None
Integer, INTENT(IN) :: a,b
Integer, INTENT(OUT) :: x,y
y=a+b
x=2*a+3*b
End Subroutine MySub
using System;
using System.Runtime.InteropServices;
namespace AlReTest
{
class Program
{
[DllImport(@"D:\...\AltRetTest.dll", CallingConvention=CallingConvention.StdCall)]
public static extern int MySub(int a, int b, [Out] int x, [Out] int y);
static void Main(string[] args)
{
int a = 4;
int b = 3;
int x = 0;
int y = 0;
MySub(a, b, x, y);
Console.WriteLine(x);
Console.WriteLine(y);
Console.WriteLine(MySub(a, b, x, y));
}
}
}
以下是我得到的答案: x=0,y=0,MySub(a,b,x,y)=17
我对VisualC编程有点陌生,但我认为上面的结果意味着两条语句,即“a+b”和“2*a+3*b”已经计算过,但没有分配给x和y,后者(2*a+3*b)已经分配给函数MySub本身!我在C#中使用了OutAttributes,在FORTRAN中也使用了Intent[in],Intent[Out],但没有一个更改结果。我将非常感谢任何帮助或建议。像你一样,我认为
意图(OUT)
将意味着通过引用传递。但情况似乎并非如此。因此,您需要在FORTRAN中添加以下内容以强制按引用传递:
!DEC$ ATTRIBUTES REFERENCE :: x,y
C端函数的正确声明是:
可以这样称呼:
MySub(a, b, out x, out y)
请注意,您需要使用out
关键字,以便将指向输出变量的指针传递给本机代码。您确实需要使用out
或ref
来确保调用代码看到修改后的值
还要注意,本机函数不返回值。只是巧合,返回值通过了一个寄存器,该寄存器碰巧包含了上次执行的计算结果。我按照您的建议@David,仍然得到相同的答案。如果您告诉我们您在Fortran中使用的编译器,可能会有所帮助。首先,我使用了out修饰符,结果没有变化,然后我使用了ref和out,正如您所提到的,结果变为0、0和一个八位数,如14394268!!!!有趣的是,每次我运行代码时,这个数字都会改变。我使用Compaq Visual Fortran解决了这个问题,我添加了“!DEC$ATTRIBUTES REFERENCE::X,Y'引用到我的FORTRAN代码中,并在c#代码中使用了out修饰符,得到了正确的结果。谢谢@davideines,我从你的第一句评论中意识到,out的意图并不意味着我们都预期的参考。因此需要编译器的详细信息。但从那以后我就离开了,没有机会深入挖掘。干得好,把我打败了。我会在适当的时候更新答案。您使用的是哪种Fortran编译器?@ClickRick阅读下面答案上的评论,我使用的是Compaq Visual Fortran 6.6。通过在我的FORTRAN DLL中添加一个引用属性解决了这个问题。正如我所看到的(在我询问之后您回答了这一点),但您和David显然已经讨论过了,所以没有进一步评论。