web-dev-qa-db-ja.com

Fortranでのモジュール、サブルーチン、および関数の正しい使用

Fortranプログラムに関数を追加するときに、tinterfaceブロックについて最近学びました。すべてうまく動作しますが、今度はインターフェイスブロックに2つ目の関数を追加します。

これが私のインターフェースブロックです。

interface
    function correctNeighLabel (A,i,j,k)
    integer :: correctNeighLabel
    integer, intent(in) :: i,j,k
    integer,dimension(:,:,:),intent(inout) :: A
    end function

    function correctNeighArray (B,d,e,f)
        character :: correctNeighArray
    integer, intent(in) :: d,e,f
    character, dimension(:,:,:),intent(inout) :: B
    end function
end interface

私には思えますが、これは最良の選択肢ではないかもしれません。

私はサブルーチンを調べましたが、それが正しい解決策であるとは確信がありません。私がやっていることは比較的簡単で、サブルーチンに引数を渡す必要がありますが、私が見たすべてのサブルーチンはa)複雑です(つまり、関数には複雑すぎます)、b)引数を取りません、彼らは渡されることなく変数を操作するかのように動作します。

私は実際にモジュールを適切に検討していませんが、私が見たところから使用するのは正しいことではありません。

いつ、どのように使用するのが最適ですか?

28
Pureferret

モジュールは常に正しいものです;-)

非常に単純なF90プログラムがある場合、「含む」ブロックに関数とサブルーチンを含めることができます。

 program simple
   implicit none
   integer :: x, y
   x = ...
   y = myfunc(x)
 contains
   function myfunc(x) result(y)
     implicit none
     integer, intent(in)  :: x
     integer              :: y
     ...
   end function myfunc
 end program

そうすれば、関数/サブルーチンのインターフェイスはプログラムで認識され、インターフェイスブロックで定義する必要はありません。

より複雑なプログラムでは、すべての関数/サブルーチンをモジュールに保持し、必要に応じてロードする必要があります。したがって、インターフェイスを定義する必要もありません。

 module mymod
   implicit none
   private
   public :: myfunc
 contains
   function myfunc(x) result(y)
     implicit none
     integer, intent(in)  :: x
     integer              :: y
     ...
   end function myfunc
 end module mymod

 program advanced
   use mymod, only: myfunc
   implicit none
   integer :: x, y
   x = ...
   y = myfunc(x)
 end program advanced

モジュールとプログラムは(実際には)別のファイルに置くことができますが、モジュールは実際のプログラムの前にコンパイルする必要があります。

40
alexurba

既に言われたことを支持し、拡張する。プロシージャ(サブルーチンと関数)をモジュールに入れて「使用」すると、インターフェイスの一貫性の自動チェックが簡単になります。他の方法には欠点があります。インターフェイスブロックを使用してインターフェイスを定義する場合、インターフェイス、プロシージャ自体、および呼び出しの2つではなく、3つの項目を維持する必要があります。変更を加える場合、一貫性を保つために3つすべてを変更する必要があります。モジュールを使用する場合、変更する必要があるのは2つだけです。インターフェイスブロックを使用する理由は、ソースコード(プリコンパイルされたライブラリなど)にアクセスできない場合、またはソースコードが別の言語(たとえば、ISO Cバインディング経由でCコードを使用している場合)にある場合です。

「含む」アプローチの欠点は、含まれるプロシージャが親プログラムのローカル変数をすべて継承することです。これはあまりモジュール化されておらず、この「機能」を忘れると非常に混乱する可能性があります。

17
M. S. B.

alexurbaとMSBの答えは、いつものように正しくて便利です。モジュールについてもう少し詳しく説明しましょう-モジュールが進むべき道である(そして、そうである)場合、インターフェースは何ですか?

モジュール内の関数とサブルーチンの場合、そのモジュールがusesするものはすべて自動的にそれらのインターフェースを見ることができます。インターフェイスは、モジュールがコンパイルされるときに生成されます(その情報は、とりわけ、モジュールをコンパイルするときに生成される.modファイルに入ります)。そのため、自分で作成する必要はありません。同様に、CONTAINedサブプログラムを使用する場合(MSBに同意すると、混乱しやすく、役立つことがわかります。 closures または 入れ子になったサブルーチン) 外部サブルーチンよりも)、メインプログラムはすでにインターフェイスを明示的に「見る」ことができ、それを書く必要はありません。

インターフェイスブロックは、できないときに-コンパイラが明示的なインターフェイスを生成できない場合、または何かをしたい場合に使用します与えられたものとは異なります。 1つの例は、Fortran 2003で C-Fortranの相互運用性 を使用する場合です。その場合、FortranコードはCライブラリ(たとえば)にリンクし、Cルーチンへの正しいfortranインターフェイスを生成する方法がありません。あなたのために-あなたはあなた自身のインターフェースブロックを書くことによってそれを自分でしなければなりません。

別の例は、サブルーチンへのインターフェイスを既に知っているが、サブルーチンを背後に「隠す」ための新しいインターフェイスを作成する場合です。たとえば、整数と実数に作用するルーチンがある場合などです。 、どちらかで同じルーチン名を呼び出し、コンパイラーが引数に基づいてソートできるようにしたい場合。このような構成体は generic routines と呼ばれ、Fortran 90から使用されています。その場合、この新しい汎用ルーチンへのインターフェイスを明示的に作成し、そのインターフェイスブロック内の「実際の」ルーチンへのインターフェイスをリストします。

16
Jonathan Dursi