複雑な宣言にも慣れておこうと思って,関数へのポインタを使った表現を書いてみました。実用にならないようなパズルはやっても意味がないんですけれど,それなりに使いそうなのは,配列や構造体に関数を収める方法です。まぁ,こんな感じでしょうか。
#include <stdio.h>
int
foo(void)
{
puts("100");
return 10;
}
int
bar(void)
{
puts("200");
return 20;
}
int
main(int argc, char *argv[])
{
int (*hoge[])(void) = {foo, bar};
struct _st {
int (*func_foo)(void);
int (*func_bar)(void);
} st;
st.func_foo = &foo;
st.func_bar = &bar;
foo();
bar();
hoge[0]();
hoge[1]();
printf("%p\n", &hoge[0]);
printf("%p\n", &hoge[1]);
st.func_foo();
st.func_bar();
printf("%p\n", &st.func_foo);
printf("%p\n", &st.func_bar);
return 0;
}
ここは練習なので,読み易いように引数が無い関数を収めてみました。実行した結果はこんな感じになります。
aian:~ % ./func
100
200
100
200
0xbfbfe560
0xbfbfe564
100
200
0xbfbfe558
0xbfbfe55c
当たり前ですけど,アドレスを求めるところは、別の数値が入るかもしれません。
C でちょっとオブジェクト指向ちっくなことをしたくなるとき,構造体を typedef するってのはよくあることだと思います。で,もうちょっと進めると,その構造体の中に関数(メソッド?)を含めたくなることがよくあるんですね。構造体だからクラスのようなメンバ変数の保護機能みたいなもんは無いけれども,発想としては同じようなもんですもんね(違うか?)。アクセサは要らないにしても,メンバ変数を使ってゴニョゴニョ操作したいってのはあると思います。
例えば,libxslt なんかを使うときに,
XSLT xslt = xsltNew();
if (xslt == NULL) {
fprintf(stderr, "Cannot create XSLT object\n");
exit(1);
}
xslt->source = foo_xml;
xslt->style = bar_xslt;
xmlDocPtr doc = xslt->proc(); /* Processing ... */
if (doc == NULL) {
fprintf(stderr, "%s", xslt->error());
exit(1);
}
みたいな書き方をしたいんです。まぁ,ただのカッコツケなんですけどね。
こういうもんを書くには,初めの例みたいに宣言する必要があります。最初の hoge が,関数へのポインタの配列を宣言しているところで,その次が構造体に関数(へのポインタ)を入れてみたところ……。アドレスの表示はあまり意味がありません(int へのポインタだね,というだけ)。
とりあえず,こんな感じで書けば,コードもうまくまとめられそうな感じがします。難点は冗長になることくらいかな……。