2

Fortran 90 プログラムから C 関数を呼び出しています ( Fortran 90 を使用する必要があります)。この C 関数は、いくつかの引数を取り、浮動小数点ポインターを返します。返されたデータを Fortran コードで正しく出力できないようです。非常に大きな数値が表示されるだけです(これはポインターのアドレスだと思います)。

REAL Fortran 変数を引数として渡し、C 関数でそれらを設定し (Fortran が参照渡しするように)、データにアクセスすることに成功しました。ただし、これはレガシー関数が使用するメソッドであるため、ポインターを戻り変数として返す必要があります (これを再実装しています)。

Fortran 90 で、C 関数から返された非文字 (実数、整数など) ポインターからデータにアクセスする方法はありますか? (注: ISO C バインディングは Fortran 2003 以降専用であるため、使用できません。) 以下に、何をしようとしているのかについてのアイデアを示しました...

ありがとう!

Fortran プログラム

program test_real
    real, dimension(10) :: realpt
    integer nbr
    integer i
    real :: a=1.0
    real :: b=2.0
    real :: c=3.0

    nbr = 9
    realpt = getpointer(a, b, c)

    do 10 i = 1, nbr
        print *,"return: ",realpt(i)
10  continue

stop
End

C 関数

float* getpointer(float *a, float *b, float *c) {
    float *rfl = (float *) calloc(9,sizeof(float));
    int i=0;

    for(i=0;i<3;i++) {
        rfl[i] = *a;
    }
    for(i=3;i<6;i++) {
        rfl[i] = *b;
    }
    for(i=6;i<9;i++) {
        rfl[i] = *c;
    }
    return(rfl);
}   // End of getpointer function

出力

return:   3.1661344E+07
return:   3.1661344E+07
return:   3.1661344E+07
return:   3.1661344E+07
return:   3.1661344E+07
return:   3.1661344E+07
return:   3.1661344E+07
return:   3.1661344E+07
return:   3.1661344E+07
4

3 に答える 3

4

このステートメントは、「ISOCバインディングはFortran2003以降専用であるため使用できません。」奇妙です。F90をサポートする現在のコンパイラは、F2003のほとんどまたはすべてもサポートします。

Eric Urbanが指摘しているように、もちろんFortran内で配列の割り当てを行うのが最も簡単です(実際には、配列のスライスまたはブロードキャストを使用して、入力を簡単に行うことができます)。ただし、この形式をとる呼び出しが必要なCルーチンがあると仮定すると、 CとFortran間のポータブルインターフェイスにISO_C_BINDINGモジュールを使用するだけです。

program test_real
    use, intrinsic :: iso_c_binding
    real(kind=c_float), pointer :: realpt(:)
    type(c_ptr) :: ptr
    integer :: nbr
    integer :: i
    real :: a=1.0
    real :: b=2.0
    real :: c=3.0

    interface
       function getpointer(a, b, c) result(ptr) bind(C,name="getpointer")
           use, intrinsic :: iso_c_binding
           implicit none
           type(c_ptr) :: ptr
           real(kind=c_float) :: a, b, c
        end function getpointer
      end interface

    nbr = 9
    ptr = getpointer(a, b, c)
    call c_f_pointer(ptr, realpt, [nbr])

    print *,"return: ",realpt
end

コンパイルして実行すると

$ gcc -c fooc.c
$ gfortran -c foo.f90
$ gfortran -o foo foo.o fooc.o
$ ./foo
 return:    1.0000000       1.0000000       1.0000000       2.0000000       2.0000000       2.0000000       3.0000000       3.0000000       3.0000000

なんらかの方法でこれを実行して7年以上前のコンパイラの制限を回避しようとすると、移植性のない脆弱な方法がたくさんありますが、心を痛める価値はありません。

更新:古いFortranの一部に触れる(または再コンパイルする)ことができない場合は、少なくともCプログラムのF2003ラッパーを作成し、古いFortranをそれにリンクさせることができます。

foowrapper.f90:

module wrapper

contains

subroutine wrapgetpointer(outarr)
    use, intrinsic :: iso_c_binding
    implicit none

    real, intent(out), dimension(:) :: outarr
    real(kind=c_float), pointer :: realpt(:)
    type(c_ptr) :: ptr
    integer :: nbr = 9
    real(kind=c_float) :: a, b, c

    interface
       function getpointer(a, b, c) result(ptr) bind(C,name="getpointer")
           use, intrinsic :: iso_c_binding
           implicit none
           type(c_ptr) :: ptr
           real(kind=c_float) :: a, b, c
        end function getpointer
      end interface

    a = 1.
    b = 2.
    c = 3.
    ptr = getpointer(a, b, c)
    call c_f_pointer(ptr, realpt, [nbr])

    outarr(1:nbr) = realpt
end subroutine wrapgetpointer

end module wrapper

foo.f90:

program test_real
    use wrapper

    real, dimension(9) :: array
    call wrapgetpointer(array)

    print *,"return: ",array
end

コンパイルと実行:

$ gfortran -c foowrapper.f90
$ gfortran -c foo.f90
$ gcc -c fooc.c
$ gfortran -o foo foo.o foowrapper.o fooc.o
$ ./foo
 return:    1.0000000       1.0000000       1.0000000       2.0000000       2.0000000       2.0000000       3.0000000       3.0000000       3.0000000
于 2013-03-22T20:22:14.497 に答える
1

コードに暗黙的な none を入れると、必要な結果が得られない理由がわかります。

Fortran の配列値関数は、通常、関数が結果を書き込むメモリ内のアドレスである「隠し」パラメーターを渡すことによって実装されます。これは、ユースケースとあまり共通点がありません。

Fortran 90 に固執する場合、これを行う方法はありません。何らかの拡張機能を使用する必要があります。

F2003 からの C 相互運用性は、F90 の拡張機能であることに注意してください...

(Cray ポインターも同様ですが、拡張機能を使用する必要がある場合は、どれを選択するかを知っています。)

于 2013-03-22T20:28:46.903 に答える
0

ラッパーソリューションを実装することにはなりませんでした。Fortran 2003 を使用できない状況でうまくいくように思われるのは、Cray ポインターです。新しいコンパイラでこれらの実行可能性がどうなるかはわかりませんが、私が使用している F90 コンパイラ (Intel ifort 9.1) ではうまく機能します。

Cray ポインターは、返された C ポインターと関連付けて使用できます。たとえば、Fortran で float 配列への Cray ポインターを宣言するには、次のようにします。

real, dimension(10) :: realpt
pointer (ptemp,realpt) 
nbr = 9

そして、次のように C 関数を呼び出すことができます。

    ptemp = getpointer(a, b, c)    
    do 10 i = 1, nbr        
        print *,"return: ",realpt(i)
10  continue

Cray ポインターの使用方法を説明するリソースを次に示します。

http://gcc.gnu.org/onlinedocs/gfortran/Cray-pointers.html

于 2013-03-26T19:33:59.300 に答える