web-dev-qa-db-ja.com

INCLUDEとFortranのモジュールの違い

useステートメントでモジュールを使用することと、includeステートメントで分離ファイルを使用することの実際的な違いは何ですか?つまり、プログラム全体で頻繁に使用されるサブルーチンがある場合、それをモジュール内に配置するか、別のファイルに書き込んで、プログラムの他のすべての部分に含める必要があるのはいつまたはなぜですか。中古?

また、モジュールに入れることを目的としたすべてのサブルーチンを別々のファイルに記述し、モジュール内でincludeを使用することをお勧めしますか?特に、サブルーチン内のコードが長い場合は、コードをより適切に整理するために(そうすれば、すべてのサブルーチンがmodにパックされますが、編集する必要がある場合は、迷路のようなコードを通過する必要はありません)。

17
Nordico

2つのマップ間の概念的な違いから、非常に重要な実際的な違いまで。

INCLUDE行はソースレベルで動作します-単純な(「ダム」)テキストの包含を実現します。インクルード行に「ファイル名」の特別なプロセッサ解釈がない場合(実際にはファイルである必要はありません)、完全なソースをプログラマーが手動で簡単にスプライスしてコンパイラーに供給することができます。 -そう-ソースのセマンティクスでこれまで。インクルードされたソースには、単独で実際の解釈はありません。その意味は、インクルードされたソースを参照するインクルード行が表示されるコンテキストに完全に依存します。

モジュールは、プログラムのはるかに高いエンティティレベルで動作します。つまり、コンパイラがソースが実際に記述していることを考慮しているレベルで動作します。モジュールは、そのダウンストリームユーザーとは別にコンパイルでき、コンパイルされると、コンパイラは、モジュールがプログラムに提供できるものを正確に認識します。

通常、インクルード行を使用している人が行うことは期待実行することは、モジュールが実際に実行したこと設計実行することです。

問題の例:

  • エンティティ宣言は複数のステートメントに分散する可能性があるため、含まれているソースによって記述されたエンティティは、期待したものではない可能性があります。次のソースが含まれていると考えてください。

    _INTEGER :: i_

    単独では、これは名前iを整数スカラー(またはおそらく関数?誰が知っているか!)として宣言しているように見えます。ここで、上記を含む次のスコープについて考えてみます。

    _INCLUDE "source from above"_
    DIMENSION :: i(10,10)

    iはランク2の配列になりました!おそらくあなたはそれをポインターにしたいですか?割り当て可能ですか?ダミーの議論?おそらくそれはエラーにつながるか、おそらくそれは有効なソースです!暗黙のタイピングをミックスに投入して、潜在的な楽しみを実際に複雑にします。

    モジュールで定義されたエンティティは、モジュールによって「完全に」定義されます。使用範囲に固有の属性(VOLATILE、アクセシビリティなど)は変更できますが、基本的なエンティティは同じままです。名前の衝突は明示的に呼び出され、USEステートメントのrename句を使用して簡単に回避できます。

  • Fortranには、ステートメントの順序に関する制限があります(仕様ステートメントは、実行可能ステートメントなどの前に配置する必要があります)。インクルードされたソースもこれらの制限の対象となります。これもインクルードポイントのコンテキストでは、ソース定義のポイントではありません。

    いくつかの完全に鈍いエラーメッセージ、またはさらに悪いことに、コンパイラによる誤ったコードのサイレント受け入れのために、ステートメント関数定義(仕様部分)と割り当てステートメント(実行可能部分)の間のソースのあいまいさとうまく混ぜ合わせてください。

    モジュールを参照するUSEステートメントが表示される場所には要件がありますが、実際のモジュールプログラムユニットのソースは、その使用ポイントから完全に独立しています。

  • 関連する手順間で共有されるグローバルな状態があり、使用したい場合は、一般的なブロックと、それに関連するシーケンス関連付けの基本概念を紹介します...

    シーケンスの関連付けは、エラーが発生しやすく、柔軟性がなく、最適化に反する時代錯誤である、基礎となる初期のFortranプロセッサ実装の不幸なブリードスルーです。

    モジュール変数は、共通のブロックとそれに関連する悪を完全に不要にします。

  • インクルード行を使用していた場合は、一般的に使用されるプロシージャのソースを実際にはインクルードしないことに注意してください(最初の段落の提案は、コンパイラからの構文エラーの沼地になります)。通常行うことは、プロシージャのinterfaceを説明するソースを含めることです。重要なプロシージャの場合、インターフェイスを説明するソースは、プロシージャの完全なソースとは異なります。つまり、同じものの2つのソース表現を維持する必要があることを意味します。これはエラーが発生しやすいメンテナンスの負担です。

    前述のように、コンパイラはモジュールプロシージャのインターフェイスの知識を自動的に取得します(コンパイラの知識は、プロシージャのコードを実際に見たため「明示的」であるため、「明示的インターフェイス」という用語になります)。プログラマーがこれ以上何もする必要はありません。

    上記の結果は、外部サブプログラムをまったく使用すべきではないということですただし反対の非常に正当な理由がある場合(おそらく循環的または過度に広範な依存関係の存在)-基本的な出発点はモジュールまたはメインプログラムにすべてを入れます。

他のポスターは、モジュールのソースコード編成の利点について言及しています。これには、関連する手順やその他の「もの」を1つのパッケージにグループ化し、内部実装の詳細へのアクセスを制御する機能が含まれます。

質問の2番目の段落にあるように、INCLUDE行が有効に使用されていることを認めます。大きなモジュールのサイズが扱いにくくなります。 F2008はサブモジュールでこれに対処しており、他にも多くの利点があります。それらが広くサポートされるようになったら、インクルードラインの回避策を放棄する必要があります。

2番目の有効な使用法は、ジェネリックプログラミング手法(テンプレートがC++で提供するもの)の言語によるサポートの欠如を克服することです。つまり、操作に関係するオブジェクトのタイプが異なる場合がありますが、それらに対して何をするかを説明するトークンシーケンスオブジェクトは基本的に同じです。言語がそれを整理するまでには、さらに10年ほどかかるかもしれません。

24
IanH

プロシージャをモジュールに配置し、それらのモジュールを使用すると、プロシージャのインターフェイスが明示的になります。これにより、Fortranコンパイラーは、呼び出し内の実際の引数とプロシージャーのダミー引数との間の整合性をチェックできます。これにより、プログラマーのさまざまなミスを防ぐことができます。 Fortran> = 90の特定の「高度な」機能には、明示的なインターフェースも必要です。たとえば、オプション引数またはキーワード引数。明示的なインターフェースがないと、コンパイラーは正しい呼び出しを生成しません。ファイルを含めるだけでは、これらの利点は得られません。

7
M. S. B.

M.S.B.の答えは素晴らしく、おそらくインクルードよりもモジュールを好む最も重要な理由です。もう少し考えを加えたいと思います。

モジュールを使用すると、コンパイルされたバイナリサイズが重要になる場合は、サイズが小さくなります。モジュールは一度コンパイルされ、useすると、コードを使用するためにそのモジュールをシンボリックにロードします。ファイルをincludeすると、実際には新しいコードがルーチンに挿入されます。 includeを頻繁に使用すると、バイナリが大きくなり、コンパイル時間が長くなる可能性があります。

モジュールを使用して、モジュール内のパブリック関数とプライベート関数、およびユーザー定義型を巧妙に使用することにより、Fortran90でOOPスタイルコーディングを偽造することもできます。それを望まない場合でも、論理的に一緒に属する関数をグループ化するための優れた方法を提供します。

3
SethMMorton