トランポリンの代わりにgotoを使う
値としてのラベル
GCCはいろいろな独自拡張があるけど,その1つにラベルの指すアドレスを値として取得する機能がある.
void *address = &&label; ... label: ... goto *address;
のように&&演算子をラベル名の前に付けると,そのラベルのアドレスを取り出すことができ,通常の値と同様に変数に格納することもできるのだ.もちろんgotoを使って格納したアドレスへジャンプすることも可能である.
トランポリンの代わりにgotoを用いる
ここでいうトランポリンとは,以下に示すように次に実行すべき関数のアドレスを戻り値で返し,大元の実行ループでは返されたアドレス値を次々とコールしていくようなスタイルのことを指す.
void *f(); void *g(); int x; void *f() { x++; return g; } void *g() { x--; return f; } int main() { void *(*r)() = f; for (;;) r = r(); return 0; }
残念ながらトランポリンスタイルは,無駄に関数のcall-returnを繰り返しているので効率が悪い.そこで,さきほどの値としてのラベルを使って無駄な関数callをなくす.
void *f; void *g; int x; void f_module(int n) { f = &&l_f; if (n) return; // 無条件にreturnすると,以降の処理がデットコードとなり削除されてしまう l_f:{ x++; goto *g; } } void g_module(int n) { g = &&l_g; if (n) return; l_g:{ x--; goto *f; } } int main() { f_module(1); g_module(1); goto *f; return 0; }