[英]How do you pass Fortran's complex type to C#?
假設我有以下 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
Fortran 代碼編譯用
gfortran -c complex_passing.f90
gfortran -fPIC -shared -o complex_passing.dll complex_passing.o
我如何在 C# 中調用這個子程序? 我嘗試了以下代碼:
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);
}
}
收效甚微 - 我的 COMPLEX 結構似乎正在返回垃圾數據:
Real: 134217760.5
Imaginary: 0
當我期望實部是 8 而虛部是 20 時。
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
當然,您根本不應該使用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
並將其與 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
此外,除了使用kind(0d0)
等之外,還有各種 C 互操作性常量和iso_fortran_env
的存儲大小常量。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.