[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
ネストした関数 とは、なにか別の関数のなかで定義された関数である。
(GNU C++ ではネストした関数はサポートしていない。)
ネストした関数の名前は、定義されたブロック内で有効である。
以下の例では、square
という名前のネストした関数を定義し、
二回呼び出している。
foo (double a, double b) { double square (double z) { return z * z; } return square (a) + square (b); } |
ネストした関数からは、それを含む関数の変数のうち、ネストした関数
が定義されている点で見えるものは全部参照可能である。
これは、レキシカル・スコーピング と呼ばれている。
例えば、以下の例では、ネストした関数が offset
という名前の変数を
親関数から継承している。
bar (int *array, int offset, int size) { int access (int *array, int index) { return array[index + offset]; } int i; … for (i = 0; i < size; i++) … access (array, i) … } |
ネストした関数は、関数内の、変数の定義が出来る場所で定義出来る。 つまり、任意のブロック中の最初の文の前になる。
ネストした関数をその名前のスコープの外側から呼び出すのは、 そのアドレスを格納したり、別の関数にアドレスを渡したりすることで 可能である。
hack (int *array, int size) { void store (int index, int value) { array[index] = value; } intermediate (store, size); } |
ここで、関数 intermediate
は、引数として store
の
アドレスを受け取る。
intermediate
が store
を呼び出すなら、
その時に store
に与えられる引数が、array
に
格納するのに使われる。
だが、この方法は、そのネストした関数を包含する関数(この例では、hack
)
が終了しない間だけ、機能する。
ネストした関数を、そのアドレスを使って、その包含関数が終了した後で 呼び出そうとすると、大変なことになる。 包含しているスコープレベルを抜けた後に呼び出しを行なうとした場合、 もはやスコープにない変数を何か参照していると、運が良ければうまく いくかもしれないが、危険を犯すことになる。 だが、ネストした関数がスコープから出てしまったものを何も 参照していない場合は、安全である。
GNU CC はネスト関数のアドレスを取るのに、トランポリン と 呼ばれる方法を使って実装している。これについて説明している 論文が ‘http://master.debian.org/~karlheg/Usenix88-lexic.pdf’ から利用できる。
ネスト関数は、包含関数内でラベルが明示的に宣言されていれば、
包含関数から継承したそのラベルにジャンプすることができる
(see section 局所的に宣言されたラベル)。
そういうジャンプは直ちに包含関数に戻り、goto
を実行したネスト関数
と中間の関数を終了する。
以下に例を示す。
bar (int *array, int offset, int size)
{
__label__ failure;
int access (int *array, int index)
{
if (index > size)
goto failure;
return array[index + offset];
}
int i;
…
for (i = 0; i < size; i++)
… access (array, i) …
…
return 0;
/* Control comes here from |
ネスト関数は常に内部リンケージとなる。
extern
付きで宣言するのは誤りである。
ネスト関数を、その定義の前に宣言する必要があるときは、
auto
を使うこと(これは、この場合以外の関数宣言では意味がない。)
bar (int *array, int offset, int size) { __label__ failure; auto int access (int *, int); … int access (int *array, int index) { if (index > size) goto failure; return array[index + offset]; } … } |
This document was generated
using texi2html 1.78.