C言語で64bit整数定数を扱う場合の注意

ƒvƒƒOƒ‰ƒ~ƒ“ƒOŒ¾Œê C ‚̐V‹@”\ および 9502 – shift of long long broken などを読むと分かる話ですが、C言語で64bit整数定数を扱う場合にはサフィックスとして l, ll, ul, ull (大文字/小文字の区別なし、u,l はどちらが先でも良い) などをつけていないとおかしなことになります。

例えば、下記のようなプログラムは意図したとおりには動きません(x86_64環境の gcc でやっています)。

$ cat hage.c
#include <stdio.h>

int main (void)
{
  unsigned long int a = 0, b = 0, c = 0;
  a = (1 << 63);
  b = (1 << 31);
  c = (1 << 15);

  printf("sizeof unsigend long int = %lu\n", sizeof(unsigned long int));
  printf("0x%lx >> 62 => 0x%lx\n", a, (a >> 62));
  printf("0x%lx >> 30 => 0x%lx\n", b, (b >> 30));
  printf("0x%lx >> 14 => 0x%lx\n", c, (c >> 14));

  return 0;
}

コンパイルしてみると警告が表示されます。また、実行すると警告が表示された部分以外の結果もおかしいことがわかります。

$ gcc -o hage hage.c
hage.c: In function 'main':
hage.c:6: 警告: 左シフト回数 >= 型の幅となっています
$ ./hage
sizeof unsigend long int = 8
0x0 >> 62 => 0x0
0xffffffff80000000 >> 62 => 0x3fffffffe
0x8000 >> 14 => 0x2

正しくは、

$ cat hage5.c
#include <stdio.h>

int main (void)
{
  unsigned long int a = 0, b = 0, c = 0;
  a = (1UL << 63);
  b = (1UL << 31);
  c = (1UL << 15);

  printf("sizeof unsigend long int = %lu\n", sizeof(unsigned long int));
  printf("0x%lx >> 62 => 0x%lx\n", a, (a >> 62));
  printf("0x%lx >> 30 => 0x%lx\n", b, (b >> 30));
  printf("0x%lx >> 14 => 0x%lx\n", c, (c >> 14));

  return 0;
}

$ gcc -o hage5 hage5.c
$ ./hage5
sizeof unsigend long int = 8
0x8000000000000000 >> 62 => 0x2
0x80000000 >> 30 => 0x2
0x8000 >> 14 => 0x2