Entry

プログラミングメモ - 「ビット幅は sizeof(T) * CHAR_BIT ではない」なんだけれども

2010年03月30日

2の冪乗関連のスニペットをちょっと書いていて,微妙に困っていたりします。こんなやつ。

#include <climits>

template<typename T>
bool isPowerOfTwo(T x) {
  return (x <= 0u) ? false : ((x & (x - 1)) == 0);
}

template<typename T>
T nextPowerOfTwo(T x) {
  if (x == 0u) {
    return 1;
  }
  --x;
  for (T i = 1; i < sizeof(T) * CHAR_BIT; i <<= 1) {
    x |= (x >> i);
  }
  return (x + 1);
}

2の冪乗を判断する関数(isPowerOfTwo)と,与えられた数値以上で最小の2の冪乗(next highest power of two)を返す関数(nextPowerOfTwo)です。符号無し整数限定。ま,こゆ仕様でも負数の冪を取る意味はあまりないので,使えないことはないんだと思います。一応,コンパイラの警告レベルを高めに設定すれば,符号付きの引数を渡したときに警告は出る(「signed と unsigned を比較してますよ」の警告)。それにしてもこれ,コンパイルエラーにしたいんだけれど,unsigned のコンセプトチェックってどうやるんだろう。boost concept check 使えばいいよ!という人は置いておくとして(そんな大それたもんじゃない)。

と,これは本題ではなくて,ちと困っているのは,以下の部分。

  for (T i = 1; i < sizeof(T) * CHAR_BIT; i <<= 1) {
    // ...
  }

有効ビット幅を計算するのに sizeof(T) * CHAR_BIT を使っているんだけれども,こゆ書き方は本当はよくありません。CHAR_BIT ってのは,char 型のビット幅が定義されている定数で,ご存知の通り大部分の処理系では8になっています。sizeof(T) はその型のバイト幅なので,まぁ,いろいろ。大抵のシステムでは,sizeof(char) == 1 とか sizeof(long) == 4 とかになっています。

テストした環境では,sizeof(long) * CHAR_BIT == 32 で,大部分の処理系で使われているビット幅と同じです。これはこれでいい。ただこの計算,ある程度有効なんですけど,厳密に言うといつも正しいわけじゃないんですね。アラインメントの関係で変な詰め物が入っている処理系では,計算結果が実際のビット幅よりも大きくなることがあったりします。

つことで,C/C++ で,ある変数型の有効ビット幅を計算する一般的な方法があるのか,少し調べていたのでした。調べてたんですけど,「違うんだよ」ということを指摘する記事はたくさんあるものの,じゃどうすんの?ということについては,見つかりませんでした。即値で定義しろとかいってんのかな。だったら,sizeof(T) * 8 でも問題ないじゃんか,とも。

ま,実際のところ,何でもいいっちゃいいんですが,こんなもん。特殊な環境に移植することになったら,後で実装してもよさそうな気がするし。なんか変に細かいところを考えすぎる癖があるんだよなー。

Trackback
Trackback URL:
Ads
About
Search This Site
Ads
Categories
Recent Entries
Log Archive
Syndicate This Site
Info.
クリエイティブ・コモンズ・ライセンス
Movable Type 3.36
Valid XHTML 1.1!
Valid CSS!
ブログタイムズ

© 2003-2012 AIAN