最近、一部の古いコードで奇妙な動作が発見されました。このコードは長い間機能していましたが、コンパイラの最適化が最大になっている一部のプラットフォーム (XBox 360、PowerPC) で壊れました。通常、未定義の動作が疑われます。
コードはおおよそ次のようになります。
#include <stdint.h>
uint32_t sign_extend16(uint32_t val)
{
return (int32_t)(int16_t)val;
}
これはエミュレーターの一部であるため、問題の操作はそれほど奇妙ではありません。通常、これは下位 16 ビットのみを考慮し、それを 32 ビットに符号拡張することを期待します。どうやら、これは長年にわたって行われていた動作でした。x86_64 では、GCC から次の結果が得られます。
0000000000000000 <sign_extend16>:
0: 0f bf c7 movswl %di,%eax
3: c3 retq
ただし、標準について理解できることから、符号なしの値を符号付き型で表すことができない場合、符号なしを符号付きに変換することは定義されていません。
[0, 32767]
他の値は未定義であるため、コンパイラは、符号なしの値が の範囲内にある必要があると想定できますか? その場合、へのキャストint16_t
とさらに別のキャストへのキャストint32_t
は何もしません。この場合、コンパイラがコードを単純な動きに変換することは合法でしょうか?