2

私は次のプログラムに少し戸惑っています

module test
   implicit none

   type TestType
      integer :: i
   end type

contains
   subroutine foo(test)
      type (TestType), intent(out) :: test
      test%i = 5 
   end subroutine

   subroutine bar(test)
      type (TestType), intent(out) :: test
      test%i = 6 
   end subroutine

end module

program hello
   use test
   type(TestType) :: t

   call foo(t)
   print *, t%i 
   call bar(t)
   print *, t%i 
end program hello

およびその派生物。それらについては後で詳しく説明します。ご存知のように、Fortranはルーチン引数を参照渡しとして転送します。つまり、test両方のダミー引数でfoo出現するエンティティbarは、のスタックで付与された同じメモリスペースprogram helloです。ここまでは順調ですね。

でポインタとして定義しprogram hellotype(TestType) :: tそれを割り当てたとします。

program hello
   use test
   type(TestType), pointer :: t

   allocate(t)

   call foo(t)
   print *, t%i
   call bar(t)
   print *, t%i

   deallocate(t)
end program hello

コードは以前と同じように機能しますが、唯一の違いは、オブジェクトがスタックではなくヒープに割り当てられていることです。

ここで、スタックに割り当てられたプログラムに戻り、その代わりにサブルーチンバーが次のように定義されていると仮定します。

 subroutine bar(test)
    type (TestType), pointer :: test
    test%i = 6 
 end subroutine

プログラムを機能させるにはヒープ割り当てバージョンを使用する必要があるため、プログラムはコンパイルされなくなります。より正確に言うと、ルーチンがダミー引数としてポインターを受け入れるように定義されている場合は、ルーチンへのポインターを渡す必要があります。一方、ダミー引数にpointerキーワードが含まれていない場合、ルーチンはポインターと非ポインターの両方を受け入れます。

これは私に不思議に思います...ダミー引数をポインタとして宣言することのポイントは何ですか?

4

1 に答える 1

5

comp.lang.fortranから再投稿、Tobias Burnsによる回答:

ここで、スタックに割り当てられたプログラムに戻り、その代わりにサブルーチンバーが次のように定義されていると仮定します。

サブルーチンbar(test)type(TestType)、pointer :: test test%i =6endサブルーチン

プログラムを機能させるには、ヒープに割り当てられたバージョンを使用する必要があるため、プログラムはコンパイルされなくなります。

これは完全には正しくありません。POINTER属性を持つダミーにALLOCATABLE変数を渡すこともできません。(実用的な)理由の1つは、ポインタアドレスがエスケープされる可能性があるため、エイリアスの問題が発生することだと思います。正式な理由は、ALLOCATABLEは単にポインターではないということです。さらに、この標準では、ヒープ、スタック、静的メモリについては説明されていません。実際、[一定の境界を持つ]ローカル配列は、スタック上ではなく静的メモリ内に作成されることがよくあります(OpenMPまたはRECURSIVE属性を使用しない場合)。したがって、コンパイラと使用するオプションによっては、「スタック」の例が「静的メモリ」の例になることもあります。

または、より正確に言うと、ルーチンがダミー引数としてポインターを受け入れるように定義されている場合は、ルーチンへのポインターを渡す必要があります。

それも完全には真実ではありません。Fortran 2008では、TARGET属性を持つ非POINTERを、INTENT(IN)属性を持つポインターダミーに渡すことができます。(ポインターのインテントは、ポインターの関連付け状況に関連しています。ポインター以外のダミーの場合、インテントは変数に格納されている値に関するものです。)

これは私に不思議に思います...ダミー引数をポインタとして宣言することのポイントは何ですか?

引数にPOINTER属性がある場合は、ポインタターゲットを割り当てて解放したり、ポインタをターゲットに関連付けたりできます。Fortran95までは、ALLOCATABLEダミー引数を使用できなかったため、次の場合はポインタを使用する必要がありました。 (ダミーの)引数をプロシージャに割り当てる必要がありました。

可能であれば、POINTERよりもALLOCATABLEを使用するようにしてください。POINTERは使いやすく、メモリリークが発生せず、コンパイラにエイリアス分析の問題が発生しません。一方、リンクリストなどを作成する場合は、ポインタが必要です。(ただし、ヒープの使用には、Fortran2008の割り当て可能なコンポーネントも使用できます。*)

*I mean:
   type t
       type(t), allocatable :: next
   end type

ここで、コンポーネントは定義されているタイプと同じタイプです。F2008以前は、これはポインターに対してのみ許可されていましたが、割り当て可能なものに対しては許可されていませんでした。

とR.メインによって

ご存知のように、Fortranはルーチン引数を参照渡しとして転送します。

それなら、どうやら私たちは間違って知っているようです。規格はそれを決して指定せず、実際、そのような指定を回避するためにかなりの道を進んでいます。あなたの誤解はよくあることですが、特に最適化をオンにした場合、ほとんどの古いコンパイラでも厳密には正確ではありませんでした。厳密な参照渡しは、多くの一般的な最適化を無効にします。

最近の標準では、参照渡しがほとんど許可されていない場合があります。この規格では、標準テキストでこれらの単語を使用していませんが、参照渡しを使用して実装するのは実用的ではないことがあります。

ポインタのようなものに取り掛かると、すべてが参照渡しであると仮定するというエラーが、以前よりも明らかになり始めます。あなたはその誤解を捨てなければならないでしょう、さもなければ多くのことがあなたを混乱させるでしょう。

他の人は残りの投稿に適切に答えたと思います。上記の点についても言及された方もいらっしゃいますが、強調したいと思います。

これがあなたの質問に答えることを願っています。

于 2010-10-15T16:29:01.303 に答える