サブルーチンを一つ書いたとします。教科書的にはこのサブルーチンの性質によっていろいろなラベルを貼り付けることができます。以下、その性質を見てみましょう。
あるルーチンfooが、内部でfooを、つまり自分自身を呼び出すとします。このとき、fooがきちんと動作するならばfooは再帰可能( recursive )です。再帰を使う有名な例として階乗計算があります。
int fact( x ) // 階乗計算 { if ( x == 0 ) return(1); else return( x * fact( x-1 ) ); // x! = x * (x-1)! を利用している }
再帰をうまく実現するには、大域変数や静的変数への書き込みを避けます。C言語であれば自動変数にのみ書き込みを行うように心がけます。アセンブリ言語でルーチンを各場合は厄介ですが、一時的にスタック上に変数領域を確保すれば大丈夫です。このようなスタック上に確保する一時領域と戻り番地などをまとめて「スタック・フレーム」と呼びます。
あるルーチンfooを実行中に割り込みが発生したとします。割り込みハンドラの中でfooを呼び、割り込みから戻ってきてfooの実行を再開します。このとき、fooの実行結果が割り込まれても割り込まれなくても正しいものであるならばfooは再入可能です( re-entrant )。再入可能性は割り込みのほかにマルチ・タスク環境ではプロセス間でも問題になります。
再入不能なルーチンの例としてprintfがあります。このルーチンは速度を稼ぐために静的変数を使うことが多く、漫然とマルチ・タスク環境で使うと正常に動作しません。このため、マルチ・タスク環境でも動くよう速度は落ちるものの安全なライブラリも用意されていることがあります。
再入可能と同様な概念に、スレッド・セーフ( thread safe )という言葉があります。こちらのほうが新しい言葉ですが、わざわざ新しい言葉を使う価値があるほど違う概念なのか私には確信が持てません。
これは最近ではほとんど論じられることがなくなりました。あるサブルーチンをどのアドレスに配置しても動くとき、再配置可能と呼びます。普通はルーチン内部のジャンプ先をラベルにしておけば勝手にリンカーが配置場所に応じて調整してくれます。従って再配置可能性が問題にされることはまずありません。
再配置可能というときには、「リンカーによって静的に再配置可能」であるというニュアンスがあります。それに対して実行時に動的に再配置可能なコードは位置独立( position independent )と呼ばれることがあります。
「再利用不能なコードなんかあるのか!」
あります。自己書き換えプログラムなどというものが大手を振ってまかり通った時代がありました。こういったプログラムは再ロードしないと安心して利用できません。再ロードなしで繰り返し利用できるコードを再利用可能( re-usable )と呼びます。
自己書き換えを使わなくても再利用不能なコードになりうることを注意してください。大域変数や静的変数を使って内部状態を保持する関数は、一般には再利用不能です。FIRフィルタ関数を例にとって考えましょう。状態変数やレジスタの状態を関数内部で大域変数に保存すると、そのルーチンではただ一つのFIRフィルタしか実現できなくなります。二つ目を動かすためには一つ目のFIRフィルタの利用を完全に放棄してからということになります。自己書き換えほど病的ではありませんが、この例ではアプリケーション内部で一個しかFIRフィルタをもてないという厳しい制限がかかります。
このような緩い再利用不能性を避けるには、引数で渡される領域に内部状態変数を保存します。この場合、呼び出す側はいくつでも状態変数用の領域を用意できますから、それぞれの状態変数がお互いを壊す恐れはありません。
C++のようなオブジェクト指向言語は、インスタンス変数によって自然に再利用可能なコードを実現します。
上にあげたような概念はアセンブリ言語時代によく用いられたものであり、いくつかの概念はコンパイラの普及とともに風化し始めています。しかし、DSP向けにアセンブリ言語でプログラムを書くときには知っておいたほうがいいでしょう。
⇒次はあふれと精度