max()マクロの解釈

id:selvaggio:20060403が紹介していたコードを解釈してみる。

#define max(T) (((T)(-1)<0)?(((unsigned long long)(-1)>>(65-sizeof(T)*8))):((T)((unsigned long long)(-1))) )
T型で表現できる最大値を返す。
T型とは、[signed | unsigned][char | short | int | long | long long]
のこと。

まず、大量の括弧は演算子の優先度によって、マクロの意味がかわらないための工夫だから無視していいだろう。

あと、三項演算子(?:)はみづらいから、if文っぽく書き換えてみる。

if((T)(-1)<0){
  (unsigned long long)(-1) >> (65-sizeof(T)*8);
}else{
  (T)(unsigned long long)(-1);
}

まず、最初の条件分岐、(T)(-1) < 0 というのは、0xFFF...FFFが負の数と解釈されるかどうか、つまりunsignedなのかsignedなのかを調べている。

簡単だから、さきにunsignedなelse節を考える。この場合、0xFFF...FFFがそのまま最大値になるので、0xFFF...FFFを目的の型にキャストする。

最後に、signedな場合を考えてみる。これは、0xFFFF FFFF FFFF FFFF(-1)をキャストして、0x0FF...FFFのように最上位ビットが0な数字を作っている。

例えば、Tがlong longの場合で考えてみる。long longは8バイト(64ビット)なので、0x0FFF FFFF FFFF FFFFを作りたい。このためには0xFFFF FFFF FFFF FFFFを1個右にシフトすればいい。だから、65-sizeof(long long)*8で1という数字を求めている。


で、思ったんだけど、65という数字はlong longが8バイトであることに依存しているから、sizeof(long long)で書き換えたほうが移植しやすいんでない?

#define MAX_SIZE (sizeof(long long)+1)
#define max(T) (((T)(-1)<0)?(((unsigned long long)(-1)>>(MAX_SIZE-sizeof(T)*8))):((T)((unsigned long long)(-1))) )