Supongamos que tengo el siguiente código Fortran
subroutine COMPLEX_PASSING(r, i, c) !DEC$ ATTRIBUTES DLLEXPORT::COMPLEX_PASSING REAL*8 :: r, i COMPLEX*8 :: c c = cmplx((r * 2), (i * 2)) return endEl código Fortran fue compilado con
gfortran -c complex_passing.f90 gfortran -fPIC -shared -o complex_passing.dll complex_passing.o¿Cómo llamaría a esta subrutina en C#? He probado el siguiente código:
using System; using System.Runtime.InteropServices; namespace FortranCalling { class Program { static void main(string[] args) { double real = 4; double imaginary = 10; COMPLEX c = new COMPLEX(); complex_passing( ref real, ref imaginary, ref c); Console.WriteLine("Real: {0}\nImaginary: {1}", c.real, c.imaginary); Console.ReadLine(); } [StructLayout(LayoutKind.Sequential)] struct COMPLEX { public double real; public double imaginary; } [DllImport("complex_passing.dll", EntryPoint = "complex_passing_", CallingConvention = CallingConvention.Cdecl)] static extern void complex_passing(ref double r, ref double i, ref COMPLEX c); } }Con poco éxito, mi estructura COMPLEX parece estar devolviendo datos basura:
Real: 134217760.5 Imaginary: 0Cuando esperaría que la parte real fuera 8 y la parte imaginaria fuera 20.
gfortran trata el COMPLEX*8 no estándar como un complejo de 8 bytes de tamaño, con componentes reales e imaginarios de 4 bytes cada uno. En su lugar, necesita un complejo de 16 bytes, con componentes reales e imaginarios de 8 bytes cada uno ( COMPLEX*16 ) o debe cambiar el lado de C# en consecuencia.
El efecto de esto es visible con lo siguiente bajo gfortran:
complex*8 :: c8 = (8d0, 20d0) complex*16 :: c16 = 0 c16%re = TRANSFER(c8,c16) print*, c8, c16 end Por supuesto, no debería usar complex* en absoluto. La falta de coincidencia del argumento se puede ver usando complex(kind=..) .
Considere la siguiente fuente "Fortran":
subroutine s(r, i, c) real(kind(0d0)) :: r, i complex(kind(0e0)) :: c c = cmplx((r*2),(i*2)) end subroutine s interface ! Interface block required to lie to some versions of gfortran subroutine s(r, i, c) real(kind(0d0)) :: r, i complex(kind(0d0)) :: c end subroutine s end interface complex(kind(0d0)) c call s(4d0, 10d0, c) print*, c%re endy compararlo con la fuente de Fortran:
subroutine s(r, i, c) real(kind(0d0)) :: r, i complex(kind(0d0)) :: c c = cmplx((r*2),(i*2)) end subroutine s complex(kind(0d0)) c call s(4d0, 10d0, c) print*, c%re end Además, en lugar de usar kind(0d0) , etc., existen varias constantes de interoperabilidad de C y constantes de tamaño de almacenamiento de iso_fortran_env .