你如何将 Fortran 的复杂类型传递给 C#?

moo*_*les 4 c# pinvoke fortran gfortran

假设我有以下 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
end
Run Code Online (Sandbox Code Playgroud)

Fortran 代码是用

gfortran -c complex_passing.f90
gfortran -fPIC -shared -o complex_passing.dll complex_passing.o
Run Code Online (Sandbox Code Playgroud)

我如何在 C# 中调用这个子程序?我尝试了以下代码:

gfortran -c complex_passing.f90
gfortran -fPIC -shared -o complex_passing.dll complex_passing.o
Run Code Online (Sandbox Code Playgroud)

收效甚微 - 我的 COMPLEX 结构似乎正在返回垃圾数据:

Real: 134217760.5
Imaginary: 0
Run Code Online (Sandbox Code Playgroud)

当我期望实部为 8,虚部为 20 时。

fra*_*lus 5

gfortran 将非标准COMPLEX*8视为大小为 8 字节的复数,实部和虚部各为 4 字节。相反,您需要一个 16 字节的复数,其中实部和虚部各为 8 个字节 ( COMPLEX*16),或者您应该相应地更改 C# 方面。

使用 gfortran 下的以下内容可以看到这种效果:

complex*8 :: c8 = (8d0, 20d0)
complex*16 :: c16 = 0

c16%re = TRANSFER(c8,c16)

print*, c8, c16 

end
Run Code Online (Sandbox Code Playgroud)

当然,你根本不应该使用complex*。使用 可以看到参数不匹配complex(kind=..)

考虑以下“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

end
Run Code Online (Sandbox Code Playgroud)

并将其与 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
Run Code Online (Sandbox Code Playgroud)

此外,kind(0d0)还有各种 C 互操作性常量和 的存储大小常量,而不是使用等iso_fortran_env