2026-09-14
count_powers.c
/* how many powers of two (1, 2, 4, ...) fit in an int? */
int count_powers_of_two(void) {
int n = 0;
for (int i = 1; i > 0; i *= 2)
n++;
return n;
}
32ビットintなら31を返すつもりの関数です。最適化なしでは期待どおり動くのに、-O2を付けると戻ってこないことがあります。何が問題で、どう直せばよいでしょうか?
Answer
最後のi *= 2がintをオーバーフローします。符号付き整数のオーバーフローは未定義動作で、「負の値に回り込む」保証はありません。コンパイラは「オーバーフローは起きない」と仮定してよいので、「正のiを2倍しても正のまま、つまりi > 0は常に真」と判断して判定を消せます(GCCの-O2では実際に無限ループになります)。周回しない符号なし型で数え、上限を明示すれば直ります:
#include <limits.h>
int count_powers_of_two(void) {
int n = 0;
for (unsigned i = 1; i <= INT_MAX; i *= 2)
n++;
return n;
}