Skip to main content

ログ取得ツール (移転先予定地)

ビット幅1のintは何を表現できるか

Cで、ビット幅1のintを書くとしよう。

struct sample{
  int  flag:1;
};

で、この1ビットで現せる1ビット幅の整数というのは「0と1」で確定かというと実は違う。実際に確かめてみると、表現できるのは「-1と0」あるいは「0と1」の2通りがあるようだ。

#include

struct sample{ int flag:1; };

int main(int argc, char **argv) { struct sample s1; s1.flag=0; printf(“0=%d\n”, s1.flag); s1.flag++; printf(“1?=%d\n”, s1.flag); if(s1.flag>0){ printf(">0\n", s1.flag); } if(s1.flag<0){ printf("<0\n", s1.flag); } return 0; }

  • gcc-3.2.3とgcc-2.96では「-1、<0」。
  • tcc-0.9.19では-runオプションをつけて直接実行すると「-1、>0」、コンパイルすると「-1、<0」。同じコンパイラなのに相反する結果になった。
  • Sun WorkShop Compilers 5.0 98/12/15 C 5.0では「1、>0」。

「-1、<0」と「-1」と評価する処理系は一見不自然だが、トップビットが立ってる上に全部のビットが立っているし、-1というのも根拠がある。-(-1)を評価しても…えーとnegateは1を引いて全部のビットを反転するんだっけ…やっぱり-1になり、恐らく1==-1が成立するだろう。

さてどちらが正しいのか。どちらも正しいような気がする。もしかしたら不定値なのかもしれない。つまりビット幅1ならunsignedにして「1、>0」を確定させるか、不定として「!=0」であるかどうかしか判定しないか、どちらかの書き方をするしかない。もともと1ビット整数に大小関係など正確に定義することなどできないのだから。

ただ、私としてはGCCに肩入れするわけではないが、「-1」説を採りたい。理由は、そのほうが整合性があるからである。例えば2ビットで表せる符号つき整数は「-2(10)、-1(11)、0(00)、1(01)」であり、プラスになる数値よりもマイナスになる数値のほうが1つ多い。この関係はどんなビット幅のintでも同じである。ビット幅1だけを特別扱いすることはない。

ちなみにunsigned flag:1;のようにするとprintfの%d変換でも「-1」ではなく「1」になる。int:1をintにキャストしたときに-1とするか1とするかはコンパイラ依存だが、unsigned:1をintにキャストするときは必ず1になる。unsignedはトップビットで符号を判別しないしプラスにしかならないからね。役には立たないが覚えておこう。

まあでも、仕様上どうなっているのかは調べてないのでそのへんは勘弁してほしいっす。 (追記) 2003-11-02 15:03

tcc-0.9.20が出てました。試したけど0.9.19と同じだった。あと記述が間違っていた。

tccで直接実行(-runをつける)は「1、>0」ではなくて「-1、>0」でした。-1で0より大きいとはこれ如何。