9

最近、一部の古いコードで奇妙な動作が発見されました。このコードは長い間機能していましたが、コンパイラの最適化が最大になっている一部のプラットフォーム (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は何もしません。この場合、コンパイラがコードを単純な動きに変換することは合法でしょうか?

4

4 に答える 4

9

2 つの整数型間の変換が未定義の動作になることはありません。

ただし、一部の整数変換は実装定義です。

整数変換について、C は次のように言います。

(C99、6.3.1.3p3) 「それ以外の場合、新しい型は署名されており、値を表すことができません。結果が実装定義であるか、実装定義のシグナルが発生します。」

この場合に何をするかはgcc、ここに文書化されています:

http://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html

「幅 N の型への変換の場合、値は型の範囲内になるように 2^N を法として減らされます。信号は発生しません」

于 2012-02-09T23:27:20.960 に答える
-1

ユニオンの使用:

uint32_t sign_extend16(uint32_t val){
    union{
        uint32_t a;
        int32_t b;
        int16_t c;
    }o;
    o.a=val;
    o.b=o.c;
    return o.a;
}
于 2012-02-10T05:35:50.477 に答える