会社で、コンパイル時に最適化オプション(-O2)をつけたら挙動がおかしくなる、という現象が発生した。原因を調べた人が「どうも条件判定が怪しい」と言ったので、該当部分(この項目のタイトルにあるif文)についていろいろ試してみた。
まず、問題になってる環境を確かめたところ、RedHat Linux 9 の gcc-3.2.2 らしい。そこで、同じ gcc-3.2.2 がインストールしてある FreeBSD 4.7-Release5.1-Release で
#include <stdio.h> short minus(int num) { return ( num & 1 ) ? 0xff00 : 0xf000; } int main (int ac, char** av) { short x = minus(ac); if ( (short)( x & 0xff00 ) > 0 ) { printf( "PLUS\n" ); } else { printf( "MINUS\n" ); } return 0; }
というソースをコンパイルし、実行。
が表示された。0xff00 の部分を -256 に書き換えても同じ結果。-O2つきでアセンブリコードを出力したところ、0xff00 のあたりは
testl $65280, %eax
となっていた。
次に、gcc-3.3.3 がインストールされている FreeBSD 5.1-Release5.2.1-Release 環境で同じことを試したところ、最適化オプションにかかわらず "MINUS" が表示された。同様にアセンブリコードを出力したところ、0xff00 のあたりは
testw $-256, %ax
となっていた。
他に、gcc-2.7 系や gcc-3.2.3 でも試したところ、最適化オプションにかかわらず "MINUS" が表示された。
結局、
という挙動っぽい。「他のコンパイラ」と書いたのは、gcc 以外ではこの問題が発生していないため。
それにしても、RedHat9 とか FreeBSD 4.7-Release 標準の gcc に、こんなバグが潜んでたのね…
isearchマンセー (謎)
しかし、(2005-03-09時点で)「あ」を入力したときに最初にでる候補は、相当批判をあびる、ゆーことになるだろうな (謎)
*Messages* の更新情報取得には、antenna.lirs もしくは index.rdfをご利用ください。 豪傑アンテナ の LIRSからも取得可能です。
vc6/vc7.1/bcc32/iccでMINUSと表示されました.<br>ただ,理由ですが,「0xff00をshortとして扱うから」ではなくgcc-3.2.2だと「intからshortへのcastが正しく動作していないから」が正確な気がします.定数値はint型で,short + intはintに格上げされてから加算されますので.<br>(例) short a = 30000; printf("a'=%d\n", a+30000);は-5536ではなく60000と表示される.
そーでつね。
たしかに、通常の演算だと int に拡張されますね。ただ、今回のアセンブリコードを見る限り、(gcc-3.2.3/3.3.3 の -O2 は)16ビットで比較してるので、(結果として)この場合は short として扱ってるのかな、と。<br><br>ちなみに、ARM版gcc-2.95.2でクロスコンパイルしてリナザウで動かしてみたら、最適化オプションありなしにかかわらず "MINUS" でした。