使用包含来自托管代码的指针的 Fortran 类型

Working with a Fortran type containing pointer from managed code

我要使用 Fortran DLL,其中包含具有以下签名(简化)的类型:

  TYPE MyType
    INTEGER(4) :: ii
    REAL(8)    :: rr
    INTEGER(4) :: n_a0
    INTEGER(4) :: n_a1
    INTEGER(4), POINTER :: a0(:)
    REAL(8)   , POINTER :: a1(:)
  END TYPE 

显然,此类型包含指向整数和双精度数的指针。我从另一个 Fortran 代码通过以下方法顺利访问此类型。

SUBROUTINE MySub(x)
TYPE(MyType) :: x

我的目标是通过 C# 代码使用 MyTypeMySub。为此,我在 C# 代码中定义了一个结构,如下所示:

struct MyType
{
    public int ii;
    public double rr;

    public int n_a0;
    public int n_a1;

    public int[] a0;
    public double[] a1;
}

并使用以下方法访问它:

    [DllImport("my_test.dll", CallingConvention = CallingConvention.Cdecl)]
    public static extern void MySub(ref MyType t);

问题是当MySub访问非数组成员时一切正常。但是当它尝试访问数组元素时,我得到 AccessViolationException。我应该怎么做才能解决这个问题?

Fortran 指针不是 C 指针。它们不能与 C 指针互操作。

虽然指向标量的 Fortran 指针通常只是底层地址,但数组指针并非如此。数组指针使用数组描述符,因为数组可以是不连续的,并且指针还包含有关下限和上限的信息。

您应该创建另一个 Fortran 类型,它是 bind(C) 并且包含 C 指针 type(c_ptr)(在内部模块 iso_c_binding 中定义)。

然后你必须创建原始类型和新类型之间的转换并使用

设置 C 指针
c_interoperable_type%c_a0 = c_loc(old_type%a0(1))

我这里用的是第一个元素,因为数组可能无法互操作。但是,您必须自己确保数组是连续的。


如果您真的无法更改 Fortran 代码,那您就有麻烦了。当然可以找出数组地址在数组描述符中的位置并直接从 C 中使用它。但是我不推荐它,它将特定于编译器,甚至可能特定于版本。