2

Fortran と C の「マスター」を使用した次のコードがあります。sigsegv が表示されますが、その理由がわかりません。マスター C プログラムからポインターを取得し、それを Fortran ポインター形式に変換し、C ポインターが指していたデータを読み取ることになっています。特別なことは何もありませんが、それでも SigSegv です。これは、Fortran多次元配列との相互運用性の欠如を回避する唯一の方法です...(そう、Cには多次元配列がありません)。

Fortran の部分:

module ret
    implicit none
    integer, pointer :: a(:,:)
end module ret

module func
    implicit none
    contains

    subroutine initialize(cp) bind(c,name='initialize')
        use ret
        use iso_c_binding
        implicit none
        type(c_ptr) :: cp

        call c_f_pointer(cp,a,[5,5])

    end subroutine initialize

    subroutine printa bind(c,name='printa')
       use ret
       implicit none
       integer :: i,j

       do i=1,5
         do j=1,5
            print *,i,j,a(i,j)
         end do
       end do
    end subroutine printa
end module func

C パート:

#include<stdio.h>
void initialize( void *);
void printa();

int main()
 {    
  int *tab;
  tab = (int *)malloc(25 * sizeof (int *));
  int i;
  for(i=0;i<25;++i)
   tab[i]=i;
  initialize(tab);
  printa();
  printf("ok\n");
  return 0;
 }

SIGSEGV はprint *,i,j,a(i,j)、Fortran 部分の行で発生します。

編集:「整数* 8」を「整数」にdo i=1,10戻し、に戻しましたdo i=1,5。このバージョンでは、質問はまだ有効です

SIGSEGV は i=1、j=1 の場合に表示されます

4

1 に答える 1

3

他の誰かがあなたのような問題を抱えてここに来た場合に備えて、これを回答として追加しています。

示されているコードには 2 つの問題があります。まず、Klas Lindbäck によって指摘されているように、整数ポインターにメモリを割り当てています。これは問題の原因ではありません。ポインターのサイズは少なくともintそれよりも広いためです。ただし、sizeof使用可能なリソースの過剰使用を防ぐために、正しいデータ型をオペレーターに提供する必要があります。

2 番目の問題は、Fortran では引数が参照によって渡されることです。これは、C から Fortran ルーチンを呼び出す場合、アドレス演算子&を使用する必要があることを意味します。また、定数は別の定数変数に配置し、アドレスで渡す必要があります。前の問題を修正すると、C コードは次のようになります。

tab = malloc(25 * sizeof (int)); // int instead of int *
int i;
for(i = 0; i < 25; ++i)
  tab[i] = i;
initialize(&tab);                // pass tab by address

Fortran 2003 では、VALUE代わりに値渡しにするために、ダミーのルーチン引数に適用できる属性が導入されました。Fortran コンパイラがこの F2003 機能を実装している場合、cp仮引数の宣言を次のように変更できinitializeます。

type(c_ptr), value :: cp

これを行うと、tab参照渡しする必要がなくなります。

于 2012-12-14T17:06:06.637 に答える