参考文献[編集]

ウィキペディアから、無料の百科事典
ナビゲーションにジャンプ 検索にジャンプ

コンピュータプログラミングサブルーチンのシーケンスであるプログラム命令ユニットとしてパッケージ特定のタスクを実行します。このユニットは、特定のタスクを実行する必要があるプログラムで使用できます

サブルーチンは、プログラム内で定義することも、多くのプログラムで使用できるライブラリー個別に定義することもできます。さまざまなプログラミング言語では、サブルーチンは、ルーチンサブプログラム関数メソッド、またはプロシージャと呼ばれる場合があります技術的には、これらの用語はすべて異なる定義を持っています。一般的な、包括的な用語 呼び出し可能なユニットが時々使用されています。[1]

サブプログラムという名前は、サブルーチンが、より大きなプログラムまたは別のサブプログラムの1つのステップとして使用されるコンピュータープログラムとほぼ同じように動作することを示しています。サブルーチンは、プログラムの1回の実行中に、他のサブルーチンからも含めて、複数回、複数の場所から開始し、サブルーチンのタスクが完了する呼び出し後に次の命令に分岐(戻るできるようにコーディングされることがよくあります。 。サブルーチンのアイデアは、ジョン・モークリーENIACでの作業中に最初に考案し[2]、1947年1月のハーバード大学のシンポジウム「EDVACタイプのマシンの問題の準備」に記録されました。[3] モーリス・ウィルクスデビッド・ウィーラー、及びスタンリー・ギルは、一般的に、それらが呼ばれるこの概念の正式な発明と信じられる閉鎖サブルーチンを[4] [5]と対比オープンサブルーチンまたはマクロ[6]しかし、Turingは、1945年の論文で、NPL ACEの設計提案に関するサブルーチンについて議論し、差出人住所スタックの概念を発明しました。[7]

サブルーチンは強力なプログラミングツールであり[8]多くのプログラミング言語の構文は、サブルーチンの記述と使用のサポートが含まれています。サブルーチンの賢明な使用(たとえば、構造化プログラミングアプローチによる)は、多くの場合、その品質と信頼性を高めながら、大規模なプログラムの開発と保守のコストを大幅に削減します。[9]サブルーチンは、多くの場合ライブラリ収集され、ソフトウェアを共有および取引するための重要なメカニズムです。オブジェクト指向プログラミングの分野はオブジェクトメソッドに基づいています(これらのオブジェクトまたはオブジェクトクラスにアタッチされたサブルーチンです)。

コンパイルと呼ばれる方法ねじコード、実行可能プログラムは、基本的には、サブルーチン呼び出しのシーケンスです。

主なコンセプト

サブルーチンの内容はその本体であり、サブルーチンが呼び出されたり呼び出されたりしたときに実行されるプログラムコードの一部です。

サブルーチンは、呼び出し側プログラムから1つ以上のデータ値を取得することを期待するように作成できます(そのパラメーターまたは仮パラメーターを置き換えるため)。呼び出し側プログラムは、引数と呼ばれるこれらのパラメーターの実際の値を提供しますプログラミング言語が異なれば、引数を渡すために異なる規則を使用する場合があります。

大会 説明 一般的な使用
値で呼び出す 引数が評価され、値のコピーがサブルーチンに渡されます Pascal、Delphi、Simula、CPL、PL / M、Modula、Oberon、Adaなど、Algol60以降のほとんどのAlgolに似た言語のデフォルトC、C ++、Java(オブジェクトと配列への参照も値で渡されます)
参照による呼び出し 引数への参照。通常、そのアドレスが渡されます。 最もアルゴルのような後の言語の選択アルゴル60などアルゴル68、パスカル、デルファイ、Simulaの、CPL、PL / M、のModula、オベロン、エイダ、および他の多くのように、。C ++、Fortran、PL / I
結果による呼び出し パラメータ値は、サブルーチンから戻るときに引数にコピーされます。 AdaOUTパラメータ
値による呼び出し-結果 パラメータ値は、サブルーチンへのエントリ時にコピーされ、戻り時に再びコピーされます。 アルゴル、スイフトの出入りパラメータ
名前で呼ぶ マクロのように–パラメータを未評価の引数式に置き換えます Algol、Scala
定数値で呼び出す パラメータが定数として扱われることを除いて、値による呼び出しと同様です PL / I NONASSIGNABLEパラメーター、AdaINパラメーター

サブルーチン呼び出しにはコンピュータメモリ内のデータ構造の変更周辺機器への読み取りまたは書き込みファイルの作成、プログラムまたはマシンの停止、さらにはプログラムの実行の遅延などの副作用もあります。副作用のあるサブプログラムは、同じ引数で呼び出された場合でも、呼び出されるたびに異なる結果を返す場合があります。例としては、多くの言語で使用可能な乱数サブルーチンがあります。このサブルーチンは、呼び出されるたびに異なる疑似乱数を返します。副作用のあるサブルーチンが広く使用されているのは、命令型プログラミング言語の特徴です。

サブルーチンは、タスクを実行するために1つ以上の場所で再帰的呼び出すことができるようにコーディングできます。この方法では、数学的帰納法と再帰的分割統治アルゴリズムによって定義された関数を直接実装できます

1つのブール値関数を計算すること(つまり、yes / noの質問に答えること)を目的とするサブルーチンは、述語と呼ばれることがあります。では、論理プログラミング言語、多くの場合、[漠然と]彼らは主にので、すべてのサブルーチンは、述語と呼ばれている[漠然と]成功または失敗を決定します。[要出典]

値を返さない、またはnull値を返すサブルーチンは、プロシージャと呼ばれることもあります。プロシージャは通常、引数を変更し、手続き型プログラミングの中核部分です

機能

関数は値を返すサブルーチンです。[10]関数の主な目的は、複雑な計算を意味のあるチャンクに分割し、それらに名前を付けることです。[11]サブルーチンは、計算された値(戻り値)を呼び出し元に返すか、さまざまな結果値または出力パラメーターを提供する場合があります。実際、サブルーチンの一般的な使用法は数学関数を実装することです。この関数では、サブルーチンの目的は、サブルーチンに渡された引数によって値が完全に決定される1つ以上の結果を純粋に計算することです。 (例には、数値の対数または行列式の計算が含まれる場合があります。)

高水準プログラミング言語には通常、次の特定の構造が含まれています。

  • サブルーチンを構成するプログラム(本体)の部分を区切ります
  • サブルーチンに識別子(名前)を割り当てます
  • パラメータと戻り値の名前とデータ型指定します
  • 一時変数にプライベート命名スコープ提供します
  • サブルーチン内でアクセス可能なサブルーチン外の変数を特定します
  • サブルーチンを呼び出す
  • パラメータに値を指定します
  • メインプログラムには、サブプログラムのアドレスが含まれています
  • サブプログラムには、メインプログラムの関数呼び出しの次の命令のアドレスが含まれています
  • 本体内からの戻り値を指定します
  • 呼び出し側プログラムに戻る
  • 呼び出しによって返された値を破棄します
  • 通話中に発生した例外的な状態を処理します
  • サブルーチンをモジュールライブラリオブジェクト、またはクラスにパッケージ化します

いくつかのプログラミング言語のような、パスカルFortranのエイダと多くの方言BASICは、しない関数または関数副プログラム、呼び出しプログラムに明示的な戻り値を提供し、サブルーチンや手続き、区別します。これらの言語では、関数呼び出しは通常、式に埋め込まれています(たとえば、sqrt関数はとして呼び出される場合がありますy = z + sqrt(x))。プロシージャ呼び出しは、構文的にステートメントとして動作します(たとえば、printプロシージャはif x > 0 then print(x)CALLまたはGOSUBなど)などのステートメントによって呼び出されるか、明示的に呼び出されますcall print(x))。CLispは、関数とサブルーチンを区別しません。

Haskellのような厳密に関数型のプログラミング言語では、サブプログラムに副作用がない可能性があります。つまり、プログラムのさまざまな内部状態は変化しません。同じ引数で繰り返し呼び出された場合、関数は常に同じ結果を返します。値を返さないサブルーチンは、副作用を引き起こす可能性がない限り役に立たないため、このような言語は通常、関数のみをサポートします。

プログラミング言語のようなCC ++、およびC#の、サブルーチンを単に呼び出される関数は(と混同されるべきではないかもしれない数学的関数又は関数型プログラミング異なる概念です)。

言語のコンパイラは通常、プロシージャコールを変換し、明確に定義された呼び出し規約に従ってマシン命令に戻るため、サブルーチンを呼び出すプログラムとは別にサブルーチンをコンパイルできます。callステートメントとreturnステートメントに対応する命令シーケンスは、プロシージャのプロローグおよびエピローグと呼ばれます

利点

プログラムをサブルーチンに分割する利点は次のとおりです。

  • 複雑なプログラミングタスクをより単純なステップに分解する:これはデータ構造とともに構造化プログラミングの2つの主要なツールの1つです。
  • プログラム内の重複コードの削減
  • 複数のプログラム間でのコードの再利用を可能にする
  • 大規模なプログラミングタスクをさまざまなプログラマーまたはプロジェクトのさまざまな段階に分割する
  • サブルーチンのユーザーから実装の詳細隠す
  • コードのブロックを、説明関数名がコードのブロックを説明するのに役立つ関数呼び出しに置き換えることにより、コードの可読性を向上させます。これにより、関数が再利用されることを意図していない場合でも、呼び出し元のコードが簡潔で読みやすくなります。
  • トレーサビリティの改善(つまり、ほとんどの言語は、関連するサブルーチンの名前と、おそらくファイル名や行番号などのさらに多くの情報を含む呼び出しトレースを取得する方法を提供します)。コードをサブルーチンに分解しないことにより、デバッグが大幅に損なわれます

インラインコードを使用する場合と比較して、サブルーチンを呼び出すと、呼び出しメカニズムに計算オーバーヘッドが発生します。[要出典]

サブルーチンは通常、関数の入口と出口の両方で標準のハウスキーピングコードを必要とします(関数プロローグとエピローグ-通常、汎用レジスタと差出人住所を最小限に保存します)。

歴史

サブルーチンのアイデアは、コンピューティングマシンがすでにしばらく存在していた後に考案されました。算術および条件付きジャンプ命令は事前に計画されており、変更は比較的少ないですが、プロシージャ呼び出しに使用される特別な命令は、長年にわたって大幅に変更されています。マンチェスターベイビーRCA1802などの初期のコンピューターやマイクロプロセッサーには、単一のサブルーチン呼び出し命令がありませんでした。サブルーチンを実装することもできますが、プログラマーは各呼び出しサイトで呼び出しシーケンス(一連の命令)を使用する必要がありました

サブルーチンは、1945年にKonradZuseZ4実装されました

1945年、Alan M. Turingは、サブルーチンを呼び出したり、サブルーチンから戻ったりする手段として、「埋める」および「埋めない」という用語を使用しました。[12] [13]

1947年1月、ジョンモークリーは、ハーバード大学と米国海軍兵站局の共同主催による「大規模デジタル計算機械のシンポジウム」で一般的なメモを発表しました。ここで彼はシリアルおよびパラレル操作について説明し、

...マシンの構造は1ビット複雑である必要はありません。この手順に不可欠なすべての論理特性が利用可能であるため、サブルーチンをメモリ内のマシンが認識している場所に配置するためのコーディング命令を進化させ、それらを簡単に使用できるようにすることができます。

言い換えると、特定の問題に必要なサブルーチンのリストを通じて、サブルーチンAを除算、サブルーチンBを複素数乗算、サブルーチンCを一連の数値の標準誤差の評価などとして指定できます。...これらのサブルーチンはすべてマシンに格納され、コーディングで示されているように、番号で簡単に参照するだけです。[3]

Kay McNultyは、ENIACチームのJohn Mauchlyと緊密に協力し、第二次世界大戦中にプログラミングしていたENIACコンピューターのサブルーチンのアイデアを開発しました[14]彼女と他のENIACプログラマーは、ミサイルの軌道を計算するのを助けるためにサブルーチンを使用しました。[14]

Goldstineフォン・ノイマンは、サブルーチンの使用を検討し1948年8月16日付けの論文を書きました。[15]

IBM 1620Intel4004Intel8008、およびPICマイクロプロセッサなどの一部の非常に初期のコンピュータとマイクロプロセッサには、専用のハードウェアスタックを使用してリターンアドレスを格納する単一命令のサブルーチン呼び出しがあります。このようなハードウェアは、いくつかのレベルのみをサポートします。サブルーチンのネストですが、再帰的なサブルーチンをサポートできます。UNIVAC IPDP-1IBM 1130など、1960年代半ば以前のマシンは、通常呼び出し規約を使用します。これにより、呼び出されたサブルーチンの最初のメモリ位置に命令カウンタが保存されました。これにより、任意に深いレベルのサブルーチンのネストが可能になりますが、再帰的なサブルーチンはサポートされません。PDP-11(1970)は、スタックプッシュサブルーチンコール命令の最初のコンピュータのいずれかです。この機能は、任意の深さのサブルーチンネストと、再帰的サブルーチンの両方をサポートします。[16]

非常に初期のアセンブラでは、サブルーチンのサポートは制限されていました。サブルーチンは、相互に、またはメインプログラムから明示的に分離されておらず、実際、サブルーチンのソースコードは他のサブプログラムのソースコードと散在している可能性があります。一部のアセンブラは、呼び出しシーケンスと戻りシーケンスを生成するための事前定義されたマクロ提供します1960年代までに、アセンブラは通常、互いにリンクできるインラインサブルーチンと個別にアセンブルされたサブルーチンの両方をはるかに高度にサポートしていました。

ユーザー作成のサブルーチンと関数をサポートする最初のプログラミング言語の1つは、FORTRANIIでした。IBM FORTRAN IIコンパイラは、1958年に発売された ALGOL 58と他の初期のプログラミング言語にも手続き型プログラミングをサポート。

サブルーチンライブラリ

この面倒なアプローチでも、サブルーチンは非常に便利であることがわかりました。一つには、彼らは多くの異なるプログラムで同じコードの使用を許可しました。さらに、初期のコンピュータではメモリが非常に不足していたため、サブルーチンを使用するとプログラムのサイズを大幅に節約できました。

多くの初期のコンピュータは、パンチされた紙テープからプログラム命令をメモリにロードしました次に、各サブルーチンは、メインプログラム(または「メインライン」[17])の前または後にロードまたはスプライスされた個別のテープによって提供されます。そして、同じサブルーチンテープを多くの異なるプログラムで使用できます。メイン入力にパンチカード使用するコンピューターに適用される同様のアプローチサブルーチンライブラリという名前は、元々、文字通りの意味で、集合的に使用するためにテープまたはカードデッキのインデックス付きコレクションを保持するライブラリを意味していました。

自己変更コードの必要性を排除するために、コンピューター設計者は最終的に間接ジャンプ命令を提供しました。そのオペランドは、リターンアドレス自体ではなく、リターンアドレスを含む変数またはプロセッサレジスタの場所でした

これらのコンピューターでは、サブルーチンのリターンジャンプを変更する代わりに、呼び出し側プログラムがリターンアドレスを変数に格納するため、サブルーチンが完了すると、事前定義された変数で指定された場所に実行を指示する間接ジャンプが実行されます。

サブルーチンにジャンプ

もう1つの進歩は、サブルーチン命令ジャンプでした。これは、リターンアドレスの保存と呼び出し元のジャンプを組み合わせて、オーバーヘッドを大幅に最小限に抑えました。

たとえば、IBM System / 360では、プロシージャ呼び出し用に設計された分岐命令BALまたはBALRは、規則レジスタ14によって、命令で指定されたプロセッサレジスタに戻りアドレスを保存します。戻るには、サブルーチンを実行するだけで済みました。そのレジスタを介した間接分岐命令(BR)。サブルーチンが他の目的(別のサブルーチンの呼び出しなど)でそのレジスタを必要とする場合、レジスタの内容をプライベートメモリの場所またはレジスタスタックに保存します

HP 2100などのシステムでは、JSB命令は同様のタスクを実行しますが、リターンアドレスがブランチのターゲットであるメモリ位置に格納されている点が異なります。プロシージャの実行は、実際には次のメモリ位置から始まります。HP 2100アセンブリ言語では、たとえば次のように記述します。

       ..。
       JSB MYSUB(サブルーチンMYSUBを呼び出します。)
 BB ...(MYSUBが完了した後、ここに戻ります。)

メインプログラムからMYSUBというサブルーチンを呼び出します。サブルーチンは次のようにコード化されます

 MYSUB NOP(MYSUBの差出人住所用のストレージ。)
 AA ...(MYSUBの体の始まり。)
       ..。
       JMP MYSUB、I(呼び出し側プログラムに戻ります。)

JSB命令は、NEXT命令のアドレス(つまりBB)をオペランドとして指定された場所(つまりMYSUB)に配置し、その後NEXTの場所(つまりAA = MYSUB + 1)に分岐しました。次に、サブルーチンは、場所MYSUBに格納されている場所に分岐した間接ジャンプJMP MYSUB Iを実行することにより、メインプログラムに戻ることができます。

Fortranおよび他の言語のコンパイラーは、利用可能な場合、これらの命令を簡単に利用できます。このアプローチは、複数レベルの呼び出しをサポートしていました。ただし、サブルーチンの戻りアドレス、パラメーター、および戻り値には固定メモリー位置が割り当てられていたため、再帰呼び出しは許可されませんでした。

ちなみに、同様の方法が1980年代初頭にLotus 1-2-3によって使用され、スプレッドシート内の再計算の依存関係を発見しました。すなわち、位置を格納するために各セル内に予約されたリターンアドレス。以来循環参照が自然再計算のために許可されていない、これは非常にのような小型コンピュータ上で限られたメモリ内のスタックのためのスペースを確保せずにツリーウォークを可能にするIBM PC

コールスタック

サブルーチン呼び出しの最新の実装では、スタックデータ構造の特殊なケースである呼び出しスタックを使用して、サブルーチンの呼び出しと戻りを実装します。プロシージャを呼び出すたびに、スタックの最上位にスタックフレームと呼ばれる新しいエントリが作成されます。プロシージャが戻ると、そのスタックフレームがスタックから削除され、そのスペースが他のプロシージャ呼び出しに使用される場合があります。各スタックフレームには、対応する呼び出しのプライベートデータ含まれます。これには通常、プロシージャのパラメータと内部変数、およびリターンアドレスが含まれます。

呼び出しシーケンスは、通常の命令のシーケンス(縮小命令セットコンピューティング(RISC)および非常に長い命令ワード(VLIW)アーキテクチャでまだ使用されているアプローチ)によって実装できますが、1960年代後半以降に設計された多くの従来のマシンには、その目的。

コールスタックは通常、メモリの連続した領域として実装されます。スタックの最下部がこの領域内の最低アドレスか最高アドレスかは任意の設計上の選択であるため、スタックはメモリ内で前方または後方に大きくなる可能性があります。ただし、多くのアーキテクチャは後者を選択しました。[要出典]

一部の設計、特に一部のForth実装では、2つの別々のスタックを使用しました。1つは主に制御情報(リターンアドレスやループカウンターなど)用で、もう1つはデータ用です。前者はコールスタックであるか、そのように機能し、プログラマーは他の言語構造を介して間接的にのみアクセスできましたが、後者はより直接アクセスできました。

スタックベースのプロシージャコールが最初に導入されたとき、重要な動機は貴重なメモリを節約することでした。[要出典]このスキームを使用すると、コンパイラは、各プロシージャのプライベートデータ(パラメータ、リターンアドレス、およびローカル変数)用にメモリ内に個別のスペースを予約する必要がありません。いつでも、スタックには、現在アクティブな(つまり、呼び出されたがまだ返されていない)呼び出しのプライベートデータのみが含まれます。プログラムが通常ライブラリからアセンブルされる方法のために、数千のサブルーチンを含むプログラムを見つけることは珍しくありませんでした(そして今でもそうです)。[要出典]このようなプログラムの場合、コールスタックメカニズムはかなりの量のメモリを節約できます。実際、コールスタックメカニズムは、自動メモリ管理の最も初期の最も単純な方法と見なすことができます

ただし、コールスタックメソッドのもう1つの利点は、同じプロシージャへのネストされた各呼び出しがプライベートデータの個別のインスタンスを取得するため、再帰的なサブルーチン呼び出しが可能になることです。

遅延スタッキング

コールスタックメカニズムの欠点の1つは、プロシージャコールとそれに対応するリターンのコストが増加することです。[説明が必要]追加のコストには、スタックポインタのインクリメントとデクリメント(および一部のアーキテクチャでは、スタックオーバーフローのチェック)、絶対アドレスではなくフレーム相対アドレスによるローカル変数とパラメータへのアクセスが含まれます。コストは、実行時間の増加、プロセッサの複雑さの増加、またはその両方で実現される可能性があります。

このオーバーヘッドは、プロシージャ呼び出しを行わずに戻るリーフプロシージャまたはリーフ関数最も明白で好ましくありません。[18] [19] [20]そのオーバーヘッドを減らすために、多くの最近のコンパイラーは、本当に必要になるまで呼び出しスタックの使用を遅らせようとします。[要出典]たとえば、プロシージャPの呼び出しでは、呼び出されたプロシージャのリターンアドレスとパラメータを特定のプロセッサレジスタに格納し、単純なジャンプでプロシージャの本体に制御を移すことができます。プロシージャPが他の呼び出しを行わずに戻った場合、呼び出しスタックはまったく使用されません。Pの場合別のプロシージャQを呼び出す必要がある場合は、コールスタックを使用して、Qが戻った後に必要になるレジスタの内容(リターンアドレスなど)を保存します。

CC ++プログラミング言語、サブプログラムは呼ばれる関数(さらにとして分類メンバ関数に関連付けられている場合、クラス、またはフリー機能[21]ではありません)。これらの言語は、void関数が値を返さないことを示すために特別なキーワード使用します。C / C ++関数には、アドレスがパラメーターとして渡される変数の変更などの副作用が発生する可能性があることに注意してください。例:

void Function1 (){ / *いくつかのコード* / }    

この関数は値を返さないため、スタンドアロン関数として呼び出す必要があります。 Function1();

int Function2 (){  
  5を返す; 
}

この関数は結果(数値5)を返し、呼び出しは式の一部にすることができます。 x + Function2()

char Function3 int number {   
  char selection [] = { 'S' 'M' 'T' 'W' 'T' 'F' 'S' };         
  選択を返す[番号]; 
}

この関数は、0から6までの数値を、対応する曜日の頭文字に変換します。つまり、0から「S」、1から「M」、...、6から「S」です。それを呼び出した結果は、変数に割り当てられる可能性がありますnum_day = Function3(number);

void Function4 int * router_to_var {   
  *ポインタ_to_var ++ ;
}

この関数は値を返しませんが、アドレスがパラメーターとして渡される変数を変更します。で呼び出されFunction4(&variable_to_increment);ます。

SmallBasicの例

()                               'サブルーチンを呼び出します

サブ                              'サブルーチン
    TextWindowを開始します。WriteLine "これはMicrosoftSmall Basicのサブルーチンの例です。"   'サブルーチンの機能
EndSub                                   'サブルーチンを終了します。

上記の例でExample()は、サブルーチンを呼び出します。[22]実際のサブルーチンを定義するには、Subキーワードを使用する必要があり、サブルーチン名はSub。の後に続きますコンテンツが続いた後、 EndSub入力する必要があります。

Visual Basic 6言語、サブプログラムは呼ばれる関数またはサブルーチン(あるいはメソッドクラスに関連付けられています)。 Visual Basic 6は、と呼ばれるさまざまな用語を使用して、パラメーターとして渡されるものを定義します。デフォルトでは、未指定の変数はバリアント型として登録され、ByRef(デフォルト)またはByValとして渡すことができます。また、関数またはサブが宣言されると、パブリック、プライベート、またはフレンドの指定が与えられ、宣言されたモジュールまたはプロジェクトの外部からアクセスできるかどうかが決まります。

  • 値による[ByVal] –アドレスを渡す代わりに、値のコピーを渡すことにより、引数の値をプロシージャに渡す方法。その結果、変数の実際の値は、渡されたプロシージャによって変更できません。
  • 参照による[ByRef] –値のコピーを渡す代わりに、変数のアドレスを渡すことにより、引数の値をプロシージャに渡す方法。これにより、プロシージャは実際の変数にアクセスできます。その結果、変数の実際の値は、渡されるプロシージャによって変更される可能性があります。特に指定のない限り、引数は参照によって渡されます。
  • パブリック(オプション)–関数プロシージャがすべてのモジュールの他のすべてのプロシージャにアクセスできることを示します。Option Privateを含むモジュールで使用する場合、この手順はプロジェクト外では使用できません。
  • プライベート(オプション)–関数プロシージャは、宣言されているモジュール内の他のプロシージャにのみアクセスできることを示します。
  • フレンド(オプション)–クラスモジュールでのみ使用されます。Functionプロシージャはプロジェクト全体で表示されますが、オブジェクトのインスタンスのコントローラーには表示されないことを示します。
プライベート 関数 Function1 ()
    'ここにいくつかのコードが
関数を終了します 

この関数は値を返さないため、スタンドアロン関数として呼び出す必要があります。 Function1

Private  Function  Function2 () as  Integer 
    Function2  =  5 
End  Function

この関数は結果(数値5)を返し、呼び出しは式の一部にすることができます。 x + Function2()

Private  Function  Function3 ByVal  intValue  as  Integer  as  String 
    Dim  strArray 6  as  String 
    strArray  =  Array "M"  "T"  "W"  "T"  "F"  "S"  "S" 
    Function3  =  strArray intValue 
End  Function

この関数は、0から6までの数値を、対応する曜日の頭文字、つまり0から「M」、1から「T」、...、6から「S」に変換します。それを呼び出した結果は、変数に割り当てられる可能性がありますnum_day = Function3(number)

プライベート 関数 Function4 ByRef  intValue  as  Integer 
    intValue  =  intValue  +  1 
End  Function

この関数は値を返しませんが、アドレスがパラメーターとして渡される変数を変更します。Function4(variable_to_increment)で呼び出されます。

PL / Iの例

PL / Iと呼ばれる手順が通過することができるディスクリプタような文字列の長さ及び配列境界などの引数に関する情報を提供します。これにより、手順をより一般的にすることができ、プログラマーがそのような情報を渡す必要がなくなります。デフォルトでは、PL / Iは参照によって引数を渡します。2次元配列の各要素の符号を変更する(簡単な)サブルーチンは、次のようになります。

  change_sign:procedure(array);
    array(*、*)floatを宣言します。
    配列=-配列;
    change_signを終了します。

これは、次のようにさまざまな配列で呼び出すことができます。

  / *最初の配列の境界は-5から+10および3から9 * /
  array1(-5:10、3:9)floatを宣言します。
  / * 2番目の配列の境界は1から16および1から16です* /
  array2(16,16)floatを宣言します。
  change_sign(array1);を呼び出します。
  change_sign(array2);を呼び出します。

ではPythonのキーワードは、def関数を定義するために使用されます。関数の本体を形成するステートメントは、同じ行で継続するか、次の行で開始してインデントする必要があります。[23]次のサンプルプログラムは、「Helloworld!」を出力します。次の行に「ウィキペディア」が続きます。

def  simple_function ():
    print 'Hello world!' 
    print 'Wikipedia' 
simple_function ()

ローカル変数、再帰、および再入可能性

サブプログラムは、一定量のスクラッチスペースを利用すると便利な場合があります。つまり、中間結果を保持するためにそのサブプログラムの実行中に使用されるメモリ。このスクラッチスペースに格納されている変数ローカル変数と呼ばれ、スクラッチスペースはアクティベーションレコードと呼ばれます。アクティベーションレコードには通常、サブプログラムの終了時に制御をどこに戻すかを指示するリターンアドレスがあります。

サブプログラムには、呼び出しサイトの数と性質を指定できます。再帰がサポートされている場合、サブプログラムはそれ自体を呼び出すことさえあり、同じサブプログラムの別のネストされた実行が発生する間、その実行を一時停止させます。再帰は、いくつかの複雑なアルゴリズムを単純化し、複雑な問題を分解するための便利な手段です。帰納言語は通常、呼び出しごとにローカル変数の新しいコピーを提供します。プログラマーがローカル変数の値を呼び出し間で同じに保ちたい場合は、一部の言語で静的と宣言するか、グローバル値または共通領域を使用できます。フィボナッチを見つけるためのC / C ++の再帰サブルーチンの例を次に示します。

int Fib int n {   
  if n <= 1 {    
    nを返す; 
  }
  Fib n - 1 + Fib n - 2 );を返します。       
}

Fortranのような初期の言語は、変数が静的に割り当てられ、戻りアドレスの場所も割り当てられていたため、最初は再帰をサポートしていませんでした。PDP-8などの1960年代後半以前のほとんどのコンピュータは、ハードウェアスタックレジスタをサポートしていませんでした。[要出典]

PL / ICなどのALGOLの後の最新の言語は、ほとんど常にスタックを使用します。通常、ほとんどの最新のコンピューター命令セットでサポートされ、サブプログラムの実行ごとに新しいアクティベーションレコードを提供します。そうすれば、ネストされた実行は、進行中の他の中断された実行への影響を気にすることなく、ローカル変数を自由に変更できます。ネストされた呼び出しが蓄積されると、中断されたサブプログラムごとに1つのアクティブ化レコードで構成される呼び出しスタック構造が形成されます。実際、このスタック構造は事実上どこにでもあるため、アクティベーションレコードは一般にスタックフレームと呼ばれます

Pascal、PL / I、Adaなどの一部の言語は、ネストされたサブルーチンもサポートしています。ネストされたサブルーチンは、外部(親)サブルーチンのスコープ内でのみ呼び出すことができるサブルーチンです。内部サブルーチンは、それらを呼び出した外部サブルーチンのローカル変数にアクセスできます。これは、ディスプレイとも呼ばれるアクティベーションレコード内に追加のコンテキスト情報を格納することによって実現されます

同じサブプログラムの別の実行がすでに進行中であっても、サブプログラムを適切に実行できる場合、そのサブプログラムは再入可能であると言われます。再帰サブプログラムは再入可能である必要があります。複数のスレッドが互いに干渉することを恐れずに同じサブプログラムを呼び出すことができるため、再入可能なサブプログラムはマルチスレッドの状況でも役立ちます。でIBM のCICS トランザクション処理システム準リエントラントは、多くのスレッドで共有されたアプリケーション・プログラムのため、多少制限の少ないが、同様の要件でした。

ではマルチスレッド環境で、一般的に複数のスタックがあります。コルーチンまたは遅延評価を完全にサポートする環境では、スタック以外のデータ構造を使用して、アクティブ化レコードを格納できます。

強く型付けされた言語、時々 、同じ名前を持つ多くの機能を有することが望ましいが、異なる種類のデータ上で動作し、または異なるパラメータプロファイルです。たとえば、平方根関数は、実数、複素数値、または行列を操作するように定義できます。それぞれの場合に使用されるアルゴリズムは異なり、返される結果も異なる場合があります。同じ名前で3つの別々の関数を作成することにより、プログラマーはデータのタイプごとに異なる名前を覚える必要がないという便利さを持っています。さらに、実数に対してサブタイプを定義して、正の実数と負の実数を分離できる場合、2つの関数を実数に対して記述できます。1つはパラメーターが正の場合に実数を返し、もう1つはパラメーターが正の場合に複素数値を返します。ネガティブ。

、オブジェクト指向プログラミングと同じ名前を持つ関数の一連の異なるパラメータプロファイル又は異なる種類のパラメータを受け入れることができ、各機能をすると言われているオーバーロード

C ++でのサブルーチンのオーバーロードの例を次に示します

#include <iostream> 

double Area double h double w { return h * w ; }          

double Area double r { return r * r * 3.14 ; }          

int main (){  
  二重rectangle_area =エリア3 4 )。    
  double circle_area = Area 5 );   

  std :: cout << "長方形の面積は" << rectangle_area << std :: endl ;      
  std :: cout << "円の面積は" << circle_area << std :: endl ;      
}

このコードには、同じ名前の2つの関数がありますが、パラメーターが異なります。

別の例として、サブルーチンは、方向を受け入れるオブジェクト作成し、画面上のこれらのポイントへのパスをトレースする場合があります。コンストラクターに渡すことができるパラメーターは多数あります(トレースの色、開始x座標とy座標、トレース速度)。プログラマーがコンストラクターが色パラメーターのみを受け入れることができるようにしたい場合は、色のみを受け入れる別のコンストラクターを呼び出すことができます。これにより、他のすべてのパラメーターのデフォルト値のセットを渡すすべてのパラメーターを使用してコンストラクターが呼び出されます( XとYは通常、画面の中央に配置されるか、原点に配置され、速度はコーダーが選択した別の値に設定されます)。

PL / Iには、GENERICさまざまなタイプの引数で呼び出される一連のエントリー参照の総称名を定義する属性があります。例:

  DECLARE gen_name GENERIC(
                      名前WHEN(FIXED BINARY)、
                      炎WHEN(FLOAT)、
                      パス名それ以外の場合 
                           );

エントリごとに複数の引数定義を指定できます。「gen_name」を呼び出すと、引数がFIXED BINARYの場合は「name」、FLOATの場合は「flame」などが呼び出されます。引数が一致しない場合は、「pathname」が呼び出されます。

クロージャ

クロージャは、それが作成された環境から撮影し、その変数の一部の値を持つサブプログラム一緒です。クロージャはによって導入されたLispプログラミング言語の顕著な特徴だったジョン・マッカーシー実装によっては、クロージャーが副作用のメカニズムとして機能する場合があります。

サブルーチンのコーディングに関する多数の規則が開発されています。多くの開発者は、名前付けに関して、サブルーチンの名前は、特定のタスクを実行するとき動詞照会を行うときは形容詞変数の置換に使用するときは名詞にするというアプローチを採用しています。

一部のプログラマーは、サブルーチンが1つのタスクのみを実行する必要があり、サブルーチンが複数のタスクを実行する場合は、より多くのサブルーチンに分割する必要があると提案しています。彼らは、サブルーチンはコード保守の重要なコンポーネントであり、プログラムでのそれらの役割は区別されたままでなければならないと主張しています

モジュラープログラミング(コードモジュラー化)の支持者は、各サブルーチンが他のコードへの依存を最小限に抑えるべきであると主張しています。たとえば、グローバル変数の使用は、サブルーチンとこれらのグローバル変数の間に緊密な結合を追加するため、この観点の支持者によって一般的に賢明ではないと見なされます。そのような結合が必要ない場合、彼らのアドバイスは、代わりに渡されたパラメーターを受け入れるようにサブルーチンをリファクタリングすることです。ただし、サブルーチンに渡されるパラメーターの数を増やすと、コードの可読性に影響を与える可能性があります。

リターンコード

その主な効果または通常の効果に加えて、サブルーチンは、実行中に発生した可能性のある例外的な状態について呼び出し側プログラムに通知する必要がある場合があります。一部の言語およびプログラミング標準では、これは多くの場合、通常および例外的な条件をエンコードする、サブルーチンによって標準の場所に配置される整数値である戻りコードを介して行われます。

/ 360 IBMシステム戻りコードはサブルーチンから予想された場合、戻り値は、しばしば、それが直接的として使用することができるように、4-の倍数であるように設計された分岐テーブルしばしば直後に位置する分岐テーブルへのインデックス余分な条件付きテストを回避するために命令を呼び出し、効率をさらに向上させます。システム/ 360 アセンブリ言語、1は例えば、記述します。

           BAL 14、SUBRTN01はサブルーチンに移動し、R14にリターンアドレスを格納します
           B TABLE(15)は、reg 15の戻り値を使用して、ブランチテーブルにインデックスを付けます。 
*適切なブランチ命令に分岐します。
表BOK戻りコード= 00GOOD}
           BBADリターンコード= 04無効な入力}ブランチテーブル
           BERROR戻りコード= 08予期しない状態}

サブルーチン呼び出しの最適化

サブルーチンの呼び出しには、引数の受け渡し、サブプログラムへの分岐、呼び出し元への分岐など、実行時のオーバーヘッド大きくなりますオーバーヘッドには、特定のプロセッサレジスタの保存と復元、コールフレームストレージの割り当てと再利用などが含まれることがよくあります。[必要な例]一部の言語では、各サブルーチン呼び出しは、サブルーチンのリターンコードの自動テストまたは発生する可能性のある例外の処理も意味します。オブジェクト指向言語のオーバーヘッドの重要な原因は、メソッド呼び出しに集中的に使用される動的ディスパッチです。

プロシージャに副作用がある場合は適用できない、一見明らかなプロシージャ呼び出しの最適化がいくつかあります。たとえば、式(f(x)-1)/(f(x)+1)ではf、2回の呼び出しで異なる結果が返される可能性があるため、関数を2回呼び出す必要があります。さらに、x最初の呼び出しで値が変更された可能性があるため、2番目の呼び出しの前にの値を再度フェッチする必要があります。サブプログラムに副作用があるかどうかを判断することは非常に困難です(実際、ライスの定理により決定不可能です)。したがって、これらの最適化は純粋に関数型プログラミング言語では安全ですが、典​​型的な命令型プログラミングのコンパイラーは通常、最悪の事態を想定する必要があります。

インライン化

このオーバーヘッドを排除するために使用される方法は、各呼び出しサイトでのサブプログラムの本体のインライン展開またはインライン化です(サブルーチンに分岐して戻るのではありません)。これにより、呼び出しのオーバーヘッドが回避されるだけでなく、コンパイラーは、呼び出し時のコンテキストと引数を考慮に入れることで、プロシージャーの本体をより効果的最適化できます。挿入された本体は、コンパイラーによって最適化できます。ただし、プログラムにサブルーチンへの呼び出しが1つしかない場合を除いて、インライン化すると通常、コードサイズが大きくなります。

「サブルーチン」という用語は、1990年代以降、テレビや映画で数え切れないほど使用されてきました。現在に設定されることもあれば、遠い将来に設定されることもありますが、コンピュータープログラミングハッキングを含むプロット要素は、この概念を呼び起こす可能性があります。多くの場合、それはしばしば誤用されます。

も参照してください

  1. ^ 米国選挙支援委員会(2007)。「特別な意味を持つ単語の定義」自主投票システムのガイドライン2012年12月8日にオリジナルからアーカイブされまし取得した2013年1月14日を
  2. ^ Subrata Dasgupta(2014年1月7日)。それはバベッジから始まりました:コンピュータサイエンスの起源オックスフォード大学出版局。pp。155–。ISBN 978-0-19-930943-6
  3. ^ a b J.W. Mauchly、「EDVACタイプのマシンの問題の準備」(1947)、Brian Randell(Ed。)、The Origins of Digital Computers、Springer、1982。
  4. ^ Wheeler、DJ(1952)。「プログラムでのサブルーチンの使用」(PDF)-ACM '52に関する1952年のACM全国会議(ピッツバーグ)の議事録NS。235. doi10.1145 /609784.609816
  5. ^ ウィルクス、MV; ウィーラー、DJ; ギル、S。(1951年)。電子デジタルコンピュータ用のプログラムの準備アディソン-ウェスリー。
  6. ^ Dainith、ジョン(2004)。" "サブルーチンを開きます。 "コンピューティングの辞書"Encyclopedia.com 2013年1月14日取得
  7. ^ Turing、Alan M.(1945)、自動コンピューティングエンジン(ACE)の開発提案に関するAM Turing博士によるレポート:1946年2月にNPLの実行委員会に提出コープランド、BJ、編で転載(2005)。アランチューリングの自動コンピューティングエンジンオックスフォード:オックスフォード大学出版局。NS。383. ISBN 0-19-856593-3
  8. ^ ドナルドE.クヌース(1997)。The Art of Computer Programming、Volume I:FundamentalAlgorithmsアディソン-ウェスリー。ISBN 0-201-89683-4
  9. ^ O.-J. ダール; EWダイクストラ; CAR Hoare(1972)。構造化プログラミングアカデミックプレス。ISBN 0-12-200550-3
  10. ^ Wilson、Leslie B.(2001)。比較プログラミング言語、第3版アディソン-ウェスリー。NS。140. ISBN 0-201-71012-9
  11. ^ Stroustrup、Bjarne(2013)。C ++プログラミング言語、第4版アディソン-ウェスリー。NS。307. ISBN 978-0-321-56384-2
  12. ^ チューリング、アラン・マシソン(1946-03-19)[1945]、自動計算エンジン(ACE)の数学部門での開発の提案 (注:1946-03-19に国立物理研究所(イギリス)の実行委員会の前に提示されました。)
  13. ^ カーペンター、ブライアンエドワード; ドラン、ロバートウィリアム(1977-01-01)[1975年10月]。「他のチューリングマシン」コンピュータジャーナル20(3):269–279。土井10.1093 / comjnl /20.3.269 (11ページ)
  14. ^ a b ウォルター・アイザクソン(2014年9月18日)。「ENIACの女性に関するウォルターアイザクソン」フォーチュン2018年12月12日にオリジナルからアーカイブされまし20181214日取得
  15. ^ 電子計算装置の問題の計画とコーディング、Pt 2、Vol。3 https://library.ias.edu/files/pdfs/ecp/planningcodingof0103inst.pdf(関連ページについては、PDFの163ページを参照してください)
  16. ^ ガイルイススティールジュニアAIメモ443。 '「高価な手続きの呼び出し」の神話を暴く。または、有害と見なされるプロシージャコールの実装」。セクション「C. プロシージャコールの評判が悪い理由」。
  17. ^ フランク、トーマスS.(1983)。PDP-11とそのアセンブリ言語の概要Prentice-Hallソフトウェアシリーズ。プレンティスホール。NS。195. ISBN  97801349170472016年7月6取得組み立て担当者に、すべての便利なサブルーチンのソースコードのコピーを提供し、組み立て用のメインラインプログラムを提示するときに、メインラインで呼び出されるサブルーチンを教えてください[...]
  18. ^ 「ARMインフォメーションセンター」Infocenter.arm.com 2013年9月29日取得
  19. ^ 「x64スタック使用量」MicrosoftDocsMicrosoft 2019年8月5日取得
  20. ^ 「関数タイプ」Msdn.microsoft.com 2013年9月29日取得
  21. ^ 「無料関数の意味」
  22. ^ 「MicrosoftSmallBasic」www.smallbasic.com
  23. ^ 「4。その他の制御フローツール— Python3.9.7ドキュメント」