去年のクリスマスプレゼント
C言語にビットフィールドというのがある。
例えば、以下の構造体
field_test
のサイズは、32bitのシステムの場合は
int (32bit) x 2 で
8byteである。
struct
field_test {
int foo
;
int bar
;
};
だけど、以下のようにビットフィールドを使うと、foo
と bar を合わせて 32bit
なので
4byteになる。fooやbarがオーバーフローしない限りは、メモリの節約ができるというわけ。
struct
field_test {
int foo : 10
;
int bar : 22
;
};
だけども、去年の暮れ(クリスマス直前)に会社で発生したクリスマスプレゼント、もとい、ツールの障害は、上記の記述が原因であった。例えば、以下のような
field.cがあったとする
--
field.c --
#include
<stdio.h>
struct field_test
{
int foo : 10;
int bar :
22;
};
int
main(void){
struct field_test ft
;
ft.foo = -1;
printf("ft.foo = %d\n", ft.foo);
return
0;
}
--
GCCでコンパイルした場合は、特におかしなところはないように見える。
%
gcc -o field field.c
% ./field
ft.foo =
-1
ところが、Sun
の Forte
でコンパイルすると、、、
%
cc -o field field.c
% ./field
ft.foo =
1023
-1 が 1023
になっとるやんけ!
最初はデバッガかけて
ft.fooがおかしな値になってるのは分かったんだけど、その理由が全然わからず。ヘッダファイルの中の構造体のメンバ変数にビットフィールドが使われているのを見て「もしや?」と思って、調べたら上記のような現象が判明した。それでも、なんで
Forte だと ft.foo に -1
を入れると 1023
になるのか、全然意味わからず。
原因の調査でC言語のバイブル「プログラミング言語C
第2版」通称 K&R
を調べたら、以下の記述が見つかった。
「フィールドは
int
としてのみ宣言してもよいが、移植可能にするには、signed
あるいは unsigned
を明示的に指定すべきである。」(183ページ)
通常のビットフィールドが使われていない
int は、暗黙のうちに signed int
と解釈されている。つまり、マイナスの値が使える。だけども、何故か
Forte
では、ビットフィールドを使った場合に限り、int
と書いただけだと unsigned int
と解釈されていたのだった。つまり、マイナスの値が使えない。
以下のように書けば、Forte
でコンパイルしても foo
や bar
で符号付き整数が扱える。
struct
field_test {
signed int foo :
10;
signed int bar :
22;
};
最初は「なんで、ビットフィールド使った時だけ
int
の解釈を変えるんだー!Forteのアホー!」と思った。そしたら、会社の先輩が
K&R
の初版を持って来て、ビットフィールドについての説明部分を見せてくれた。そこには以下のように書いてあった。
「ビットフィールドは符号なしである。」
つまり、昔はビットフィールドを使った変数では、符号無し整数しか扱えなかったらしい。K&Rの初版から第二版までの間に、C言語の仕様が変更されて、ビットフィールドを使った変数でも符号付き整数が扱えるようになったと思われる。
もし
Forte
が昔のC言語の仕様と互換性を保つために、ビットフィールドを使った時は
int を unsgined int
と解釈しているのであれば、それほどおかしな事でもないかな、と思い直したのだった。
C言語に歴史あり、と思った出来事でした。
Posted: 木 - 1月 8, 2004 at 09:53 午後