C言語の基礎
int get(int *p) {
int v = *p;
if (p == NULL)
return -1;
return v;
}上の関数を gcc で最適化を有効にしてコンパイルすると、if (p == NULL) の判定が削除されることがある。その理由として正しいものはどれか。
- A先に *p を読んでおり、p が NULL ならそこで未定義動作なので、p は NULL でないと仮定してよいから
- BNULL との比較は、規格で常に偽になると決まっているから
- C最適化では、関数の引数を調べる if 文は呼び出し側が確かめるものとみなされ、すべて削除してよい決まりだから
答えと解説を見る
正解:A. 先に *p を読んでおり、p が NULL ならそこで未定義動作なので、p は NULL でないと仮定してよいから
p が NULL なら、先に実行する int v = *p; が NULL ポインタの参照になり、その時点で未定義動作です。コンパイラは未定義動作が起きないと仮定してよいので、*p を読めた以上 p は NULL ではないと判断し、p == NULL の判定と return -1 を取り除きます。x86-64 の gcc 13 で -O2 を付けると、関数は *p を読んで返すだけのコードになり、-O0 では判定が残ります。判定を確実に効かせるには、*p を読む前に p を確かめます。
- A. 正しい。参照が判定より先にあるので、p は NULL でないと推論されます。
- B. NULL との比較は、p が NULL なら真になります。この関数では、判定より前の *p が原因です。
- C. 引数を調べる判定は、一般には削除されません。削除されるのは、結果が決まっていると推論できる場合だけです。