2016-12-05 1 views
2

Je suis d'utiliser une DLL Fortran qui contient un type avec la signature suivante (simplifiée):Travailler avec un pointeur contenant le type Fortran de code managé

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 

De toute évidence, ce type contient des pointeurs vers des entiers et doubles. J'accède ce type par la méthode suivante à partir d'un autre code Fortran en douceur.

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

Mon but est de travailler avec cette MyType et MySub par le code C#. Pour ce faire, je définissais une structure dans mon code C# comme suit:

struct MyType 
{ 
    public int ii; 
    public double rr; 

    public int n_a0; 
    public int n_a1; 

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

et l'accès avec la méthode suivante:

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

Le problème est quand MySub les accès tout les membres non-tableau est OK . Mais quand il essaie d'accéder aux éléments du tableau, je reçois AccessViolationException. Que dois-je faire pour résoudre ce problème?

+0

J'ai également essayé de changer le type de 'a0' et' a1' en 'IntPtr' et de les allouer en utilisant' Marshal.AllocHGlobal'. Mais j'ai la même exception dans ce cas non plus. – melmi

Répondre

6

Les pointeurs Fortran ne sont pas des pointeurs C. Ils ne sont pas interopérables avec les pointeurs C.

Alors que les pointeurs Fortran vers les scalaires sont souvent juste des adresses sous le capot, ce n'est pas le cas pour les pointeurs de tableau. Les pointeurs de tableau utilisent des descripteurs de tableau, car les tableaux peuvent être non contigus et le pointeur contient également les informations sur les limites inférieure et supérieure.

Vous devez créer un autre type Fortran qui est bind(C) et qui contient des pointeurs C tels que type(c_ptr) (définis dans le module intrinsèque iso_c_binding).

Ensuite, vous devez créer une conversion entre le type original et le nouveau type et définissez les pointeurs C en utilisant

c_interoperable_type%c_a0 = c_loc(old_type%a0(1)) 

J'utilise le premier élément ici, parce que le tableau ne peut pas être interopérables. Cependant, vous devez vous assurer que le tableau est simplement contigu.


Si vous ne pouvez vraiment pas changer le code Fortran, vous avez des problèmes. Il est certainement possible de trouver où se trouve l'adresse du tableau dans le descripteur de tableau et l'utiliser directement à partir de C. Cependant, je ne peux pas le recommander, ce sera spécifique au compilateur et peut-être même spécifique à la version.