6
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

C/C++で64bit整数を使ってシフト演算をするときの注意点

Posted at

unsigned long longuint64_tなどの64bit整数では数値リテラルに接尾辞を忘れたためにビット演算を期待通りに行えないことがあります. ビット演算で謎の結果が出た時はこの辺を疑ってみるとよいでしょう.

指定した位置のビットを立てて返す関数set_bitを考えます.

#include <bits/stdc++.h>
#include <stdint.h>

using namespace std;

// vのpos桁目のビットをたてる
uint64_t set_bit(uint64_t v, uint pos)
{
  assert (1 <= pos && pos <= sizeof(uint64_t)*8);
  return v | (1 << (pos-1));
}

int main()
{
  uint is[] = {1,31,32,33,64};
  for (uint i : is) {
    uint64_t set = set_bit(0,i);
    cout << "i=" << i << endl;
    cout << set << endl;
  }
  return 0;
}

gcc5.4.0でコンパイルしたところ, これは次のような結果を返しました.

i=1
1
i=31
1073741824
i=32
18446744071562067968
i=33
1
i=64
18446744071562067968

この例の場合, 1は最大で63ビットシフトされるのでそれだけのビット幅を持たなければいけません. したがってullを付加してやれば修正できます.

@@ -7,7 +7,7 @@
 uint64_t set_bit(uint64_t v, uint pos)
 {
   assert (1 <= pos && pos <= sizeof(uint64_t)*8);
-  return v | (1 << (pos-1));
+  return v | (1ull << (pos-1));
 }
i=1
1
i=31
1073741824
i=32
2147483648
i=33
4294967296
i=64
9223372036854775808

関連リンク

INT34-C. 負のビット数のシフトやオペランドのビット数以上のシフトを行わない
UndefinedBehaviorSanitizer — Clang 5 documentation

6
7
6

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?