2017-05-30 23 views
0

単一のデータ配列セットで動作する従来のFortran 90コードがあり、複数のデータセットを持つことができるようにコードを拡張したいと考えています。残念ながら、サブルーチンのどれも入力引数を取ることはなく、すべてのデータはモジュールを通して評価されます。以下のコードはFortranのコードと似ています。Cポインタを使用してFortranモジュールのデータメンバーを追跡する

MODULE test_mod 
    IMPLICIT NONE 

    double precision, pointer :: f_x(:) 
    integer :: n = 5 
END MODULE test_mod 

SUBROUTINE alloc_x() 
    use test_mod 
    IMPLICIT NONE 

    allocate(f_x(n)) 
END SUBROUTINE alloc_x 

SUBROUTINE init_x() 
    USE test_mod 
    IMPLICIT NONE 

    f_x = 1.0 
END SUBROUTINE init_x 

SUBROUTINE dealloc_x() 
    use test_mod 
    IMPLICIT NONE 

    deallocate(f_x) 
END SUBROUTINE dealloc_x 

Fortranコードは、コードの変更少ない良好、(そこに約100の配列があり、すべての異なる形状およびサイズである)十分に複雑であるので。

割り当てられたFortran配列の場所を格納し、cポインタをモジュールに戻す2つの追加のFortranサブルーチンを作成します。

#include <stdio.h> 
#include <stdlib.h> 

void alloc_x_(); 
void init_x_(); 
void dealloc_x_(); 
void store_ptrs_(double **c_x); 
void copy_ptrs2mod_(double **c_x); 

void output_result(int entry, double* array); 

int main() 
{ 
    int i; 
    double *x[10]; 

    /* allocate array */ 
    for(i=0; i<10; i++){ 
     alloc_x_(); 
     store_ptrs_(&x[i]); 
    } 

    /* initialize array */ 
    for(i=0; i<10; i++){ 
     copy_ptrs2mod_(&x[i]); 
     init_x_(); 
     output_result(i,x[i]); 
    } 

    /* deallocate the array */ 
    for(i=0; i<10; i++){ 
     copy_ptrs2mod_(&x[i]); 
     dealloc_x_(); 
    } 
} 

void output_result(int entry, double* array){ 
    int j; 
    printf("x[%2d] = [", entry); 
    for (j = 0; j < 5; ++j) 
    { 
     if (j == 4) 
     { 
      printf("%3.1f",array[j]); 
      continue; 
     } 
     printf("%3.1f, ",array[j]); 
    } 
    printf("]\n"); 
} 

出力 - -

これら2つのサブルーチンで

SUBROUTINE store_ptrs(c_x) 
    use iso_c_binding 
    use test_mod 
    IMPLICIT NONE 

    TYPE(c_ptr) :: c_x 

    c_x = c_loc(f_x) 
END SUBROUTINE 

SUBROUTINE copy_ptrs2mod(c_x) 
    use iso_c_binding 
    use test_mod 
    IMPLICIT NONE 

    TYPE(c_ptr) :: c_x 
    CALL c_f_pointer(c_x,f_x,[n]) 
END SUBROUTINE 

、我々は、Fortranコードを変更することなく、データのつ以上のコピー(次のコードでは10コピー)を持つことができます

x[ 0] = [1.0, 1.0, 1.0, 1.0, 1.0] 
x[ 1] = [1.0, 1.0, 1.0, 1.0, 1.0] 
x[ 2] = [1.0, 1.0, 1.0, 1.0, 1.0] 
x[ 3] = [1.0, 1.0, 1.0, 1.0, 1.0] 
x[ 4] = [1.0, 1.0, 1.0, 1.0, 1.0] 
x[ 5] = [1.0, 1.0, 1.0, 1.0, 1.0] 
x[ 6] = [1.0, 1.0, 1.0, 1.0, 1.0] 
x[ 7] = [1.0, 1.0, 1.0, 1.0, 1.0] 
x[ 8] = [1.0, 1.0, 1.0, 1.0, 1.0] 
x[ 9] = [1.0, 1.0, 1.0, 1.0, 1.0] 

これにはまだ問題がありませんが、コンパイラ固有のさまざまな標準の実装に依存しているか、最近の標準との互換性により、これが機能しない可能性があります。レガシーFortran 90コードで共通の問題でなければならないことを処理するためのこのアプローチに関するコメントやフィードバックには、大変感謝しています。

+1

'iso_c_binding'モジュールはFortran 2003まで標準化されていませんでした。 – francescalus

+2

Fortran 90は完全に廃止されました。それは忘れて、Fortran 90に準拠する必要はありません。*最も重要な問題を修正した* Fortran 95を使用しますが、Fortran 2003または2008のほうが良いでしょう。 –

答えて

0

あなたのコード/アプローチは正しいとは言いませんが、私は最初に気になるものを特定します。あなたはこれを簡単に扱うことができます。あなたは、名前がC側に、与えることをマングリングプロトタイプを持っているという事実から

void alloc_x_(); 
void init_x_(); 
void dealloc_x_(); 
void store_ptrs_(double **c_x); 
void copy_ptrs2mod_(double **c_x); 

これはFortranの手順は任意のモジュールの外にあることを示唆している(あなたがでbind(c,name='alloc_x_')などを持っていませんサブルーチン文)。 Fortran 2008の前に、モジュールがアクティブスコープで参照されなくなったときにモジュール変数が未定義になるというルールがあります。

C実行では、alloc_xが入力されます。test_modが参照されます。しかし、サブルーチンが完了するとすぐに、test_modはアクティブスコープで参照されなくなります。 Fortran 90からFortran 2003までのルールでは、モジュール変数f_xはその時点では未定義になります。その後、store_ptrsc_loc(f_x)の参照は準拠していません。

save属性をモジュールローカル変数に追加するか、Fortran 2008標準に従うことで、この問題は解決されます。ポインタ引数はスカラでなければなりません:


は、Fortran 2003のCの相互運用性の規則の下で、 f_xc_locへの有効な引数ではない、と述べました。

+1

実際にこのように動作していたコンパイラは、現在も使用しています。 –

+1

いいえ、「あなたはおそらく安全です」の1つですが、質問は基本的に言語弁護士のレベルで質問しました。私の編集では、とにかくやっかいなことでしょう... – francescalus

関連する問題