Fortranで作成したDLL内の2次元配列を動的配列で受け渡せない

解決


hymg  2010-03-19 18:51:54  No: 38054

はじめまして.

Fortranで作成した数値計算プログラムのインターフェイスを,exe単体で使用できるDelphiで作成したいと思い,最近使い始めました.
使用コンパイラのVersionは,以下です.

Delphi6 Personal Edition(Build6.240,Update Pack2)
Compaq VisualFortran 6.6C

Delphiから,Fortranで作成したDLL内のサブルーチンを呼び出して使用したいのですが,2次元の動的配列の受け渡しがうまくいかず,困っています.
色々と調べたつもりなのですが,うまくいきません.

以下のように,動的配列を宣言して使用すると,
  TIntMatrix = array of array of Longint;
IDE上で配列imxの中身を追うと,
imx((0,0,0),(0,0,0),(0,0,0))→imx()
と表示されました.

以下のように,固定長配列とすると,うまくいきます.
  TIntMatrix = array[0..2, 0..2] of Longint;
配列imxの中身は,
imx((0,0,0),(0,0,0),(0,0,0))→imx((0,0,0),(0,1,2),(0,2,4))
となりました.

------- 定義部におけるDLL利用部分(Delphi) -------
implementation
{$R *.dfm}
type
  TIntMatrix = array of array of Longint;
  procedure TestMatrixDll(imn, imx, jmn, jmx: Longint;
                          var idat: TIntMatrix);
                          stdcall; external 'Fortran_dll.dll'
                          name 'TestMatrixDll';

------- DLL利用procedure内の記述(Delphi) --------
var
  imx: TIntMatrix;
begin
  SetLength(imx, 3, 3);
  TestMatrixDll(0, 2, 0, 2, imx);
end;

------- DLL側のSUBROUTINE(Fortran) --------

SUBROUTINE TestMatrixDll(mmin, mmax, nmin, nmax, marray)
  !DEC$ ATTRIBUTES STDCALL, DLLEXPORT :: TestMatrixDll
  !DEC$ ATTRIBUTES ALIAS : "TestMatrixDll" :: TestMatrixDll
  !DEC$ ATTRIBUTES REFERENCE :: marray
   IMPLICIT NONE
   INTEGER(4), INTENT(IN) :: mmin, mmax
   INTEGER(4), INTENT(IN) :: nmin, nmax
   INTEGER(4), INTENT(OUT) :: marray(mmin:mmax, nmin:nmax)

   INTEGER :: i, j

   DO j = nmin, nmax
      DO i = mmin, mmax
         marray(i, j) = i * j
      END DO
   END DO

   RETURN
END SUBROUTINE TestMatrixDll

ポインタを使ってみようと考え,
PIntMatrix = ^TIntMatrix;
TIntMatrix = array of array of Longint;
と宣言してprocedure定義,呼び出し部もPIntMatrixとしてみましたが,うまくいきませんでした.
ちなみに,1次元の配列だと,同様の使い方でうまく動的配列も使用できました.

以上,よろしくお願いいたします.


jazzin  2010-03-20 00:02:33  No: 38055

動的配列、多次元配列と言葉は同じでも、各言語での実装のされ方は異なります。
例えばDelphiでは多次元配列は配列の配列として実装されています。
(つまり一次元目は二次元目の配列へのポインタを保持する配列となっていて連続性がない)
一方で全ての次元がメモリ上で連続している多次元配列を持つ言語もあります。
このように異なる言語間で多次元配列を受け渡すのは困難であり、
できたように見えても実は問題があるという場合がほとんどです。

1次元では成功されているようですので、2次元配列を渡すのではない回避策となってしまいますが、
2次元配列を1次元の配列に変換し、引数として各次元の要素数を渡すようにすると良いのではないでしょうか。


hymg  2010-03-20 01:33:39  No: 38056

jazzin 様

早速のご返答,ありがとうございます.
NAG[Borland DelphiからNAGライブラリを利用]
http://www.nag-j.co.jp/naglib/usingDLL/usingDLLfromBorlandDelphi.htm
においても,固定長の2次元配列のサンプルがあったのみで,途方にくれていました.

おっしゃるとおり,「たまたまできた」ような状況は望ましくないですね.
Cの関数で似たような2次元配列⇔1次元配列を扱うものを書いたことがあるので,これを移植し,ひとつプロシージャをかませてラップすることにします.

また,同様の処理は,C#では先頭アドレスを渡して配列を転置すると,動的配列のように受け渡しが可能でした.
.NETのライブラリが標準な環境が一般的になったら,C#に移行してもよいかと思っていたのですが,これも,もしかすると問題を孕んでいる可能性もありますね.

個人的には,Delphiの手軽さが気に入っているので,しばらく使ってみようと思います.

今回は,誠にありがとうございました.


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加