4

私は機械工学のバックグラウンドを持っていますが、Adaで優れたソフトウェアエンジニアリングの実践を学ぶことに興味があります。いくつか質問があります。

Q1。私が正しく理解していれば、誰かがパッケージ仕様(ads)ファイルを作成し、それをコンパイルしてから、パッケージを使用しているメインプログラムをコンパイルすることができます。後で、パッケージ本体に何を含めるかがわかったら、後者を作成してコンパイルできます。その後、メインプログラムを実行できるようになります。私はこれを試しましたが、これが良い習慣であることを確認したいと思います。

Q2。2番目の質問は、スタブ(サブユニット)とSEPARATEの使用についてです。次のようなメインプログラムがあるとします。

    WITH Ada.Float_Text_IO;
    WITH Ada.Text_IO;
    WITH Ada.Integer_Text_IO;

    PROCEDURE TEST2 IS
    A,B      : FLOAT;
    N        : INTEGER;

    PROCEDURE INPUT(A,B: OUT FLOAT; N: OUT INTEGER) IS SEPARATE;

    BEGIN -- main program
      INPUT(A,B,N);
      Ada.Float_Text_IO.Put(Item => A);
      Ada.Text_IO.New_line;
      Ada.Integer_Text_IO.Put(Item => N);
    END TEST2;

次に、別のファイルにプロシージャINPUTがあります。

separate(TEST2)
PROCEDURE INPUT(A,B: OUT FLOAT; N: OUT INTEGER) IS
   BEGIN
      Ada.Float_Text_IO.Get(Item => A);
      Ada.Text_IO.New_line;
      Ada.Float_Text_IO.Get(Item => B);
      Ada.Text_IO.New_line;
      Ada.Integer_Text_IO.Get(Item => N);
   END INPUT;

私の質問:

a)AdaGIDEは、INPUTプロシージャファイルをinput.adbとして保存することを提案します。しかし、メインプログラムtest2をコンパイルすると、次の警告が表示されます。

warning: subunit "TEST2.INPUT" in file "test2-input.adb" not found
cannot generate code for file test2.adb (missing subunits)

AdaGIDEにとって、上記の警告がメッセージの前に表示されるため、これはより多くのエラーです。

Compiling...
Done--error detected

そこで、コンパイル時にAdaGIDEから提案されたように、input.adbファイルの名前をtest2-input.adbに変更しました。メインファイルをコンパイルする際に、警告はありません。今の私の質問は、書いて大丈夫かどうかです

PROCEDURE INPUT(A,B: OUT FLOAT; N: OUT INTEGER) IS

サブユニットファイルtest2-input.adbで行ったように、または次のようなより説明的な用語を書く方がよい

PROCEDURE TEST2-INPUT(A,B: OUT FLOAT; N: OUT INTEGER) IS

プロシージャ入力には親プロシージャtest2があることを強調しますか?この考えは、前述のようにtest2-input.adbについてヒントを与えてくれたAdaGIDEから得られたものです。

b)私の次の質問:

コンパイル順序をよく理解している場合は、最初にメインファイルtest2.adbをコンパイルしてから、スタブtest2-input.adbをコンパイルする必要があります。スタブをコンパイルすると、次のエラーメッセージが表示されます。

cannot generate code for file test2-input.adb (subunit)
Done--error detected

ただし、test2.adbのバインドとリンクを実行して、プログラムを実行できるようになりました。

スタブtest2-input.adbをコンパイルしようとして間違ったことをしたのか、それともコンパイルすべきではないのかを知りたいのですが。

Q3。サブユニットを持つことの使用は何ですか?大きなプログラムを小さな部分に分割するだけですか?サブユニットのBEGINとENDの間にステートメントを入れないと、エラーが発生することはわかっています。つまり、これは常にそこにステートメントを配置する必要があることを意味します。そして、後でステートメントを書きたい場合は、サブユニットのBEGINとENDの間に常にNULLステートメントを入れて、後で後者に戻ることができます。これは実際にソフトウェアエンジニアリングが行われる方法ですか?

どうもありがとう...

4

3 に答える 3

7

Q1:それは素晴らしい習慣です。

また、パッケージ仕様を仕様として扱うことで、他の開発者に提供して、コードへのインターフェイス方法を他の開発者が理解できるようにすることができます。

Q2:AdaGIDEは実際にはすべてのコンパイルにGNATコンパイラを使用していると思います。したがって、受け入れ可能なファイル名を担当しているのは実際にはGNATです。(これは構成できますが、非常に説得力のある理由がない限り、GNAT / AdaGIDEのファイル命名規則を使用する方がはるかに簡単です。)ただし、質問に関連するのは、親を含める強い理由はありません。別のユニットの名前の一部としてのユニット。しかし、Q3の答えを見てください...

Q3:サブユニットはAdaの最初のバージョンであるAda 83で導入されました。これは、コードのモジュール化を支援し、開発とコンパイルの延期を可能にするためです。ただし、Adaソフトウェア開発の慣行では、サブユニットの使用はほとんど放棄されており、すべてのプロシージャ/機能/タスクなどの本体は、パッケージの本体ですべて維持されています。プラットフォーム固有のバージョンのサブプログラムが必要になる場合など、一部の領域では引き続き使用されますが、ほとんどの場合、使用されることはめったにありません。追跡するファイルが少なくなり、パッケージの実装コードがすべて一緒に保持されます。したがって、サブユニット機能を無視して、すべての実装コードをパッケージ本体に配置することを強くお勧めします。

于 2010-07-11T18:59:36.037 に答える
4

問題をコンポーネントパーツ(パッケージ)に分割し、それぞれが異なる側面をサポートするのはごく普通のことです。Adaを学んだ場合は、最初にパッケージの仕様を記述し、それが正しい設計である理由を(おそらく自分自身で)議論してから、それらを実装するのが普通です。そして、これは、仕様と本体をサポートするすべての言語(たとえば、C)では正常だと思います。

個人的には、バカなことをしていないことを確認するために、編集をチェックしていました。

セパレートに関しては、1つの(あまり良くない)理由は、混乱を減らし、ユニットが長くなりすぎるのを防ぐためです。もう1つの理由(私が書いたコードジェネレーターの場合)は、コードジェネレーターがUMLモデルで開発者の手書きコードを保持することを心配する必要がなかったためです。すべてのコード本体は別個のものでした。3つ目は、環境に依存する実装(たとえば、WindowsとUnix)の場合で、コンパイラーに環境ごとに異なるバージョンの個別の本体を表示させます(ただし、通常、これにはライブラリパッケージを使用します)。

コンパイラには、ファイル名、およびコンパイルできる順序に関する独自のルールがあります。GNATが認識した場合

procedure Foo is
   procedure Bar is separate;

foo.adbFooの本体が名前のファイルにあり、Barの本体がにあることを期待しています(おそらく、別のパッケージfoo-bar.adbと言うことができますが、おそらく問題の価値はありません)。ここの流れに沿って進むのが最善です。gnatmakeNaming

separate (Foo)
procedure Bar is

十分に明確です。

コンパイルすることができfoo-bar.adb、それは完全な分析を行い、コード内のほとんどすべてのエラーをキャッチします。しかし、GNATはそれ自体でこのためのコードを生成することはできません。代わりに、コンパイルするfoo.adbと、生成された1つのオブジェクトファイルにすべての個別の本文が含まれます。これを行うのは間違いありませ

GNATを使用すると、コンパイルの順序を気にする必要がなく、好きな順序でコンパイルできます。しかし、それを使用gnatmakeして、コンピューターに負担をかけるのが最善です!

于 2010-07-11T19:09:12.310 に答える
1

もちろん、すべてのパッケージ本体に何らかの実装が行われるまでプログラムがリンクしないことを除いて、実際に説明した方法で作業できます。そのため、すべてのプロシージャが次のように実装されたダミーのパッケージ本体を作成するのがより一般的だと思います。

begin
   null;
end;

そして、すべての関数は次のように実装されます。

begin
   return The_Return_Type'first; --'
end;

セパレートに関しては...私はそれらが好きではありません。私にとっては、パッケージのすべてのコードがそのパッケージ本体にあるという規則に従うことができればと思います。何らかの理由でルーチンが巨大な場合、セパレートはわずかに許容されますが、その場合、ほとんどの場合、コードをリファクタリングすることをお勧めします。ですから、私がそれを見るときはいつでも、それは大きな赤い旗です。

ファイル名に関しては、これはgnatの問題であり、Adaの問題ではありません。Gnatは、ファイルの内容の名前がファイル自体の名前を決定するというコンパイラーの珍しい立場を取りました。おそらく世界にはそれを行う他のコンパイラがありますが、私はまだ30年のコーディングで1つを見つけていません。

于 2010-07-12T13:17:30.427 に答える