Namaran

Code daily. Without assist.

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 *= 2intをオーバーフローします。符号付き整数のオーバーフローは未定義動作で、「負の値に回り込む」保証はありません。コンパイラは「オーバーフローは起きない」と仮定してよいので、「正の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;
}