私の主な質問は、なぜ配列がそのような奇妙なことをするのか、そして「クリーンな」方法で次のことを行う方法があるかどうかです。
私は現在、おおよそ以下のコードのように、foo.c
FortranプログラムとインターフェースするCプログラムを持っていbar.f90
ます。dlopen/dlsym
foo.c:
#include <dlfcn.h>
#include <stdio.h>
int main()
{
int i, k = 4;
double arr[k];
char * e;
void * bar = dlopen("Code/Test/bar.so", RTLD_NOW | RTLD_LOCAL);
void (*allocArray)(int*);
*(void **)(&allocArray) = dlsym(bar, "__bar_MOD_allocarray");
void (*fillArray)(double*);
*(void **)(&fillArray) = dlsym(bar, "__bar_MOD_fillarray");
void (*printArray)(void);
*(void **)(&printArray) = dlsym(bar, "__bar_MOD_printarray");
double *a = (double*)dlsym(bar, "__bar_MOD_a");
for(i = 0; i < k; i++)
arr[i] = i * 3.14;
(*allocArray)(&k);
(*fillArray)(arr);
(*printArray)();
for(i = 0; i < 4; i++)
printf("%f ", a[i]);
printf("\n");
return 0;
}
bar.f90:
module bar
integer, parameter :: pa = selected_real_kind(15, 307)
real(pa), dimension(:), allocatable :: a
integer :: as
contains
subroutine allocArray(asize)
integer, intent(in) :: asize
as = asize
allocate(a(asize))
return
end subroutine
subroutine fillArray(values)
real(pa), dimension(as), intent(in) :: values
a = values
return
end subroutine
subroutine printArray()
write(*,*) a
return
end subroutine
end module
主な利回りを実行します
0.0000000000000000 3.1400000000000001 6.2800000000000002 9.4199999999999999
0.000000 -nan 0.000000 0.000000
これは、Fortranが配列を正しく割り当て、指定された値を正しく格納していることを示していますが、dlsymを介してアクセスできなくなりました(そのデータで作業するとsegfaultが発生します)。固定サイズの配列でもこれを試しましたが、結果は同じです。
誰かがこの行動の理由を知っていますか?個人的には、双方向で動作するか、まったく動作しないことを期待していました。この「FortranはC配列を受け入れますが、その逆はありません」ということで、この方法でCから配列にアクセスする際に基本的な間違いがあったのではないかと思います。
もう1つの(そしてさらに重要な)質問は、これらの「正しい方法」のような配列アクセスをどのように行うかです。現在、「Fortran as .so」インターフェースに固執することが良い方法であるかどうかさえわかりません。この場合、混合プログラミングを試みることも可能だと思います。それにもかかわらず、配列の問題は残っています-これはISO Cバインディングを使用して何らかの方法で解決できることを読みましたが、まだその方法を理解できませんでした(Fortranではあまり作業していませんが、特に上記のバインディングでは作業していません) 、この問題についてのヘルプをいただければ幸いです。
編集:
さて、私はISO Cバインディングをもう少し読んで、ここで非常に便利なアプローチを見つけました。を使用C_LOC
すると、Fortran構造体へのCポインターを取得できます。残念ながら、配列へのポインタはポインタへのポインタのようであり、C配列として扱う前に、Cコードで逆参照する必要があります。
編集:
少なくとも大部分は、ウラジミールFが指摘したように、Cバインディングを使用してプログラムを動作させることができました。CファイルとFortranファイルがリンクされたので、少なくともFortranの部分ではlibdlインターフェイスを回避できます。動的Cライブラリをロードし、そこにあるシンボルの1つへの関数ポインターを取得して、それを渡す必要があります。後で計算の一部としてその関数を呼び出すFortranへの関数ポインターとして。上記の関数はdouble*s [arrays]を期待しているので、奇妙なことに、C_LOCを使用してFortran配列を渡すことができませんでした。C_LOC(array)
またC_LOC(array(1))
、正しいポインターをC関数に戻すこともできませんでした。array(1)
しかし、トリックをしました。悲しいことに、これはこれを行うための「最もクリーンな」方法ではありません。誰かが私にこれを使用してこれを行う方法のヒントを得た場合C_LOC
機能、それは素晴らしいでしょう。それにもかかわらず、私はそれがより安全な解決策であると考えるので、ウラジミールFの答えを受け入れます。