21

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

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

4

3 に答える 3

28

2 つのマップの概念上の違いは、非常に重要な実用上の違いにつながります。

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

モジュールは、プログラムのより高い実体レベル、つまりソースが実際に記述していることをコンパイラが考慮しているレベルで動作します。モジュールは、下流のユーザーから分離してコンパイルできます。モジュールがコンパイルされると、コンパイラーは、モジュールがプログラムに提供できるものを正確に認識します。

通常、インクルード行を使用している人が望んでいるのは、モジュールが実際に行うように設計されていることです。

問題の例:

  • エンティティー宣言は複数のステートメントにまたがる可能性があるため、含まれるソースによって記述されるエンティティーは、予期したものとは異なる場合があります。次のソースを含めることを検討してください。

    INTEGER :: i

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

    INCLUDE "source from above"
    DIMENSION :: i(10,10)

    iランク 2 の配列になりました。おそらく、それを POINTER にしたいですか?アロケータブル?仮引数?おそらくそれはエラーになるか、または有効なソースです! 暗黙のタイピングをミックスに投入して、潜在的な楽しみを本当に倍増させます。

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

  • Fortran には、ステートメントの順序に関する制限があります (仕様ステートメントは実行ステートメントの前に置かなければならないなど)。含まれるソースも、ソース定義のポイントではなく、 包含のポイントのコンテキストで、これらの制限の対象となります。

    ステートメント関数定義 (仕様部分) と代入ステートメント (実行可能部分) の間のソースのあいまいさとうまく組み合わせて、一部の完全にわかりにくいエラー メッセージや、さらに悪いことに、エラー コードのコンパイラによるサイレントな受け入れについて説明します。

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

  • 関連するプロシージャ間でグローバルな状態を共有したいと考えていて、インクルードを使用したいですか? 一般的なブロックと、関連するシーケンス関連の基本的な概念を紹介しましょう...

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

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

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

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

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

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

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

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

于 2013-03-27T19:55:31.173 に答える
9

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

于 2013-03-27T15:24:03.797 に答える
4

MSB の答えは素晴らしく、インクルードよりもモジュールを好む最も重要な理由でしょう。さらにいくつかの考えを追加したいと思います。

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

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

于 2013-03-27T18:28:51.183 に答える