sizeofは深い

実は、つい最近まで、Cのsizeofの値は処理系依存だと思っていたが、sizeof(char) は規格で1に決まっているようだ(unsigned char,signed charも)。


ついでに気づいた事がある。char buf[FOO]; の buf を fgets 等の関数の引数にする際、サイズを指定する引数に、sizeof buf/sizeof buf[0] でサイズを与えたりする。普通はchar型の変数の値が式の中で現れるとそれはintに拡張されるはずだ。が、しかし、sizeof buf[0] は1である。ということは、buf[0]は値でなく変数として扱われているわけだ。まあ、他の単項演算子 ++ でもその作用する項は値でなく変数な訳で、sizeofの特殊性ではないわけか。

当然のことながら、sizeof '0' になると変数でなく値なのでこれはsizeof(int)になる。また、sizeof ++i は正当だが、インクリメントは実行されない。関数呼び出しを書いても呼び出されないが、引数の型チェックはなされる。このあたりは驚きのない仕様だ。


さて、規格を斜め見してみると、キャスト演算子は、単項演算子と別立てで、キャスト演算子と書いてある。どうも優先順序もsizeofなどの単項演算子より弱そうだ。これは初めて知った。てっきり単項演算子の仲間とばかり思っていた。
実際、sizeof (float) 3 は、「3をfloatにキャストしてそのサイズを得る」じゃなくて、「sizeof(float)のうしろに単に3が続いた」と解釈され、構文エラーになる(gcc)。前者のように解釈して欲しければ、sizeof((float) 3) と書かないといけない(3を書く実質的意味がないが)。それではと思って、int i; を使って ++ (int) i を書いてみると、gcc では通る。これはおかしいと思って、gcc -ansi -pedantic でコンパイルするとちゃんとエラーになる。gcc拡張機能のようだ。


ちなみに、「C 演算子 優先」でググってみると、キャストと他の単項演算子の優先順序を同じと書いてあるページも見受けられる。なんと http://en.wikipedia.org/wiki/C_%28programming_language%29 もである。規格は斜め読みしかしてないので、直すまでの勇気はない。専門家の人あとはよろしく。


最後に、gcc で驚いたこと。gcc -traditional すると、gcc: GNU C no longer supports -traditional without -E ・・・がちょーん。もはや、K&Rは動かないのか。。。