クイズ

突然ですが問題です。以下のプログラムをx86_64アーキテクチャ(64bit)上で動かした場合の実行結果はどうなるでしょうか?

#include <stdio.h>

int main(int argc, char *argv[]) {
        unsigned long code = -1UL;

        printf("code       = %016lx\n", code);
        printf("code >> 16 = %016lx\n", code >> 16);
        printf("code >> 63 = %016lx\n", code >> 63);
        printf("code >> 64 = %016lx\n", code >> 64);
        printf("code >> 65 = %016lx\n", code >> 65);

        return 0;
}

回答は以下の通り。
(反転させて見てください)

[kaigai@masu ~]$ ./a.out
code       = ffffffffffffffff
code >> 16 = 0000ffffffffffff
code >> 63 = 0000000000000001
code >> 64 = ffffffffffffffff
code >> 65 = 7fffffffffffffff

こりゃ驚いた。別に x86_64 に限った話ではなく、i386でも同様に、シフト演算子を使う時のシフト幅は sizeof(変数) * 8 でモジュロ演算した結果に落とされてしまう。

これを知らなかったせいで、x86_64では以下のコードが無限ループに落ちてしまった。うーむ、深い。

unsigned long maps[];
u64 bitmap;

while (bitmap) {
    maps[index++] |= bitmap & (-1UL);
    bitmap = bitmap >> BITS_PER_LONG;
}

ちなみにどうやって解決したか。

while (bitmap) {
    maps[index++] |= bitmap & (-1UL);
    bitmap = ((bitmap >> BITS_PER_LONG/2)
                      >> BITS_PER_LONG/2);
}

これでいいのだ。