コンパイラ
上の関数で、コンパイラが *b の読み込みをループの外に出す最適化を、そのままでは行えない理由はどれか。
void add(int *a, int *b, int n) {
for (int i = 0; i < n; i++)
a[i] += *b;
}
- A*b は整数なので、ループの外に出すと値の精度が落ちるから
- Ba と b が同じ場所を指している可能性があり、a[i] への書き込みで *b が変わるかもしれないから
- Cポインタを引数にとる関数は、コンパイラが一切最適化してはいけない決まりだから
答えと解説を見る
正解:B. a と b が同じ場所を指している可能性があり、a[i] への書き込みで *b が変わるかもしれないから
一見すると *b はループの中で変わらないので、1回だけ読めばよさそうです。しかし呼び出し側が add(x, &x[3], n) のように、bがaの要素を指すポインタを渡すと、a[3] への書き込みで *b の値が変わります。コンパイラはこの可能性(エイリアス)を否定できないので、毎回読み直すコードを作ります。C言語ではポインタに restrict を付けて、別の場所を指すことを約束すれば最適化できます。精度の問題でも、最適化が禁止されているわけでもありません。
- A. 整数の読み込みを移動しても精度は変わりません。
- B. 正しい。aとbが重なる可能性(エイリアス)があるためです。
- C. ポインタを使う関数も最適化されます。