6
procedure questiontype;  
 begin  
  writeln ('Enter the type of question you would like...');  
  writeln ('1. Add');  
  writeln ('2. Multiply');  
  writeln ('3. Subtraction');  
  writeln ('4. Division');  
  readln (typeofquestion);  
   case typeofquestion of
    1: add;
    2: multiply;
    3: subraction;
    4: division   
else writeln ('Choose again'); 
end;
end;          

足し算、掛け算、引き算、割り算はすべて手続きです。これをメインプログラムに入れると問題なく動作しますが、これをプロシージャ自体として作成するとundeclared identifierというエラーが発生します。このような例を多くのWebサイトで調べましたが、見つかりません。

足し算、掛け算、引き算、割り算をこの中からどのようにして手続きに移すのでしょうか?

4

3 に答える 3

14

プロシージャを呼び出すルーチンの前に、プロシージャを宣言する必要があります。他のルーチンがどのように定義されているかは示されていませんが、示されているルーチンの後に宣言されていると推測されます。

したがって、コードを並べ替えるだけで、加算、乗算、減算、および除算がそれらを呼び出すプロシージャの前に定義されるようになります。

したがって、これは機能します:

procedure add;
begin
  //do something;
end;

procedure questiontype;  
begin  
  add;  
end;

しかし、これはコンパイルされません:

procedure questiontype;  
begin  
  add;  
end;

procedure add;
begin
  //do something;
end;

Pascal とそのバリアントは 1 回のパスでコンパイルされます。コンパイラが指定された時点でルーチンを認識していない場合、処理を続行できません。

Pascal は、*forward 宣言` を使用して、A が B を呼び出し、B が A を呼び出すコルーチンをサポートしています。例えば:

procedure B; forward;

procedure A;
begin
  B;
end;

procedure B;
begin
  A;
end;

当然、これは書かれているように、スタック オーバーフローで終了する無限ループです (適切です!) が、これが必要な実際の例はもちろんあります。

ただし、前方宣言が必要になることはめったになく、複雑さが増すため、可能であれば避ける必要があります。宣言を並べ替えるだけで、常に解決策を見つけることができます。

最後に、使用前に宣言が発生する順序の制約については、Brian Kernighan の有名な記事Why Pascal is Not My Favorite Programming Languageで明示的に言及されています。

于 2011-03-19T16:31:43.703 に答える
6

あなたはあなたの質問[delphi]に と同様にタグを付けている[pascal]ようですが、あなたは実際に Delphi コードを書いているのだと思います。forward次に、手順の順序とDavid が説明したディレクティブを気にする以外に、さらにいくつかのオプションがあります。

ほとんどの場合、Delphiプロジェクト (GUIまたはコンソール) は「ユニット」に分割されます。典型的なユニットは次のようになります。

unit MyUnit;

interface

const
  RANDOM_NUMBER = 17;

var
  PrintExtraNiceMessage: boolean;

procedure DoThis;
procedure DoThat;

implementation

const
  BUFFER_SIZE = 256;

procedure InitSomething;
begin
  // TODO: do some internal work...
end;

procedure DoThis;
begin
  // TODO: do something
end;

procedure DoThat;
begin
  // TODO: do something else
end;

ユニットが 2 つの部分に分かれていることに気付くでしょう。パーツinterfaceimplementationパーツです。このinterface部分には、(関数、プロシージャ、型、定数、および変数の) 宣言のみが含まれます。ここで宣言された関数とプロシージャは、セクションで定義 (つまり、実装) されimplementationます。implementationセクションで宣言されていない関数とプロシージャがセクションで定義されている可能性があることに注意してくださいinterface

壮大なアイデアは、interfaceセクションの内容がプログラム内の他のすべてのユニットから見えるのに対し、implementationセクションの内容はまさにこのユニット内でしか見えないということです。したがって、プログラム内の他のどのユニットでも、RANDOM_NUMBER定数、PrintExtraNiceMessage変数、および 2 つのプロシージャDoThisとを使用できますDoThat。ただし、このユニットでのみ使用できますInitFunction(たとえば、またはの内部 )。さらに、定数はこのユニットの外でも見えません。DoThisDoThatBUFFER_SIZE

これは非常にエレガントなアプローチです。このinterfaceセクションでは、このユニットが他のユニットでどのように使用されるか (たとえば、どのような機能があり、どのように使用されるか) を説明し、実装の詳細はセクションに「隠されています」implementation

このアプローチの利点は、少なくとも問題を解決できることです。、、、およびプロシージャが他のユニットから見えるようにする必要がある場合は、セクションで宣言する必要があります。しかし、それらは実際にプロシージャーになるまでにコンパイラーに認識されるため、セクション内のプロシージャーの下で定義 (実装) されている場合でも、これらを呼び出すことができます。しかし一方で、他のユニットにこれらの手続きを使用させることがまったく意味がない場合は、セクションで宣言するべきではなく、David が提案するようにする必要があります。これは、プロジェクトに通常のユニットがまったくない場合、つまり、addmultiplysubtractdivideinterfacequestiontypequestiontypeimplementationinterfaceprograminterfaceimplementationパーツに分割されていないファイル。

于 2011-03-19T17:55:30.490 に答える
2

OPの例には、最後の「if」にのみ適用されるelseがあることに注意してください。おそらく、1、2、または 3 を入力すると、対応するプロシージャが起動して戻り、「Choose again」が表示されます。4 を入力すると、入力されません。これは、OPが意図したように、「他のすべてが失敗した場合」にのみ最後のelseがトリガーされるCaseまたはカスケードif..else if構造によってうまく機能します。

于 2011-03-19T17:22:19.223 に答える