コンパイラ

上の関数の最後の再帰呼び出しに末尾呼び出しの最適化を行うと、どのような効果があるか。

int fact(int n, int acc) {
    if (n <= 1) return acc;
    return fact(n - 1, acc * n);
}
  1. A再帰の回数が半分になり、計算の結果も2倍速く求まる
  2. B関数がインライン展開され、再帰そのものが定数に置き換わる
  3. C呼び出しが分岐(ジャンプ)に置き換わり、再帰が深くてもスタックが増えない
答えと解説を見る

正解:C. 呼び出しが分岐(ジャンプ)に置き換わり、再帰が深くてもスタックが増えない

この関数の再帰呼び出しは、関数の最後の処理で、その結果をそのまま返しています(末尾呼び出し)。呼び出しのあとに残る処理がないので、今の関数のスタックフレームを使い回し、引数を書き換えて関数の先頭へジャンプする形に変換できます。これによりループと同じ働きになり、再帰がどれだけ深くてもスタックが増えず、あふれる心配がなくなります。再帰の回数は変わらず、nが実行時に決まるので定数にはできません。

  • A. 繰り返しの回数は変わりません。
  • B. nは実行時に決まるので、定数には置き換えられません。
  • C. 正しい。ジャンプに置き換わり、スタックが増えなくなります。
この分野を解く 分野ページへ

コンパイラのほかの問題

  1. コンパイラとインタプリタの違いとして正しいものはどれか。
  2. JITコンパイルを使う実行環境の特徴として正しいものはどれか。
  3. LLVMの基本的な構成として正しいものはどれか。
  4. コンパイラの最適化のレベルを指定するオプションで、最適化をしない設定(-O0など)がよく使われる場面はどれか。
  5. プロファイルを使った最適化(PGO)の説明として正しいものはどれか。