gcc 拡張を使うと、関数の中に関数を定義することができる。これを利用すると C でもクロージャが使えることを少し前に知ったが、ようやく理解できた…気がする。
すごい。C でもクロージャが書けるんだ。 RT @stillpedant: とりあえず変数のスコープに気をつければこんなのは動く. "gist: 330323 - GitHub" - http://j.mp/aE7YrX
— マスタカ (@masutaka) March 13, 2010
クロージャとは
C 言語のコールバック関数に近いが、引数以外の変数を自身が定義された静的スコープで解決することが最大の特徴。
…だと理解しています。^^;
コーディング例
#include <stdio.h>
/* 任意の関数 func を n 回実行するだけのライブラリ関数 */
void
dolist(void (*func)(void), int n)
{
int i;
for(i = 0; i < n; i++) {
func();
}
return;
}
int
main(void)
{
int level = 0;
void lambda(void)
{
level++;
}
printf("%d\n", level);
dolist(lambda, 1);
printf("%d\n", level);
dolist(lambda, 2);
printf("%d\n", level);
dolist(lambda, 3);
printf("%d\n", level);
return 0;
}
結果
0
1
3
6
Solaris9 の /usr/local/bin/gcc で確認した。
dolist は渡された処理(lambda)を、指定された回数分実行するだけのライブラリ関数。
ユーザ(main)は処理内容を、自分の静的スコープの中で自由に定義することができる。level を外部変数にしなくて良い点が素晴らしい。狭いスコープ大事。
lambda() を nm で確認したところ、t マークが付いていた。lambda() はスタックに展開されているわけではなく、static な関数として定義されているということ。
lambda() と level の関係はどうなっているんだろう?