18

C / C++ 標準(このリンクを参照)によると、C および C++ の >> 演算子は必ずしも符号付き数値の算術シフトではありません。ビットが右にシフトされるときに 0 (論理) または符号ビット (算術) がシフトされるかどうかは、コンパイラの実装次第です。

このコードは、符号付き整数の論理右シフトを実装するコンパイラのコンパイル時に ASSERT (失敗) するように機能しますか?

#define COMPILE_TIME_ASSERT(EXP) \
    typedef int CompileTimeAssertType##__LINE__[(EXP) ? 1 : -1]

#define RIGHT_SHIFT_IS_ARITHMETIC \
    ( (((signed int)-1)>>1) == ((signed int)-1) )

// SHR must be arithmetic to use this code
COMPILE_TIME_ASSERT( RIGHT_SHIFT_IS_ARITHMETIC );
4

3 に答える 3

6

は、私にはよく見えますよ!コンパイラを設定して、アセンブリ ファイルを出力する (またはコンパイルされたプログラムをデバッガにロードする) こともできsigned int i; i >> 1;ます。

符号付き数値の算術右シフトを実装していないコンパイラを見つけたことがあれば、ぜひ教えてください。

于 2009-10-20T22:39:43.777 に答える
1

なぜ主張するのですか?コンパイラのシフト演算子がニーズに合わない場合は、結果を符号拡張することで状況を適切に改善できます。また、ランタイムで十分な場合もあります。結局、コンパイラのオプティマイザは、コンパイル時間を実行時間から外すことができます。

template <typename Number>
inline Number shift_logical_right(Number value, size_t bits)
{
    static const bool shift_is_arithmetic = (Number(-1) >> 1) == Number(-1);
    const bool negative = value < 0;
    value >>= bits;
    if (!shift_is_arithmetic && negative) // sign extend
        value |= -(Number(1) << (sizeof(Number) * 8 - bits));
}

static const boolコンパイル時に評価できるため、shift_is_arithmeticが であることが保証されている場合true、ソルトに値するすべてのコンパイラは、if句全体とconst bool negativeデッド コードとしての構築を排除します。

注: コードは Mono のencode_sleb128function: hereから適応されます。

アップデート

算術シフトのないマシンでコンパイルを本当に中止したい場合は、プリプロセッサに依存しない方がよいでしょう。static_assert(または)を使用できますBOOST_STATIC_ASSERT

static_assert((Number(-1) >> 1) == Number(-1), "Arithmetic shift unsupported.");
于 2012-09-14T07:43:52.020 に答える
0

さまざまなコメントから、このクロスプラットフォームの使用について話しています。コンパイラがプラットフォーム用にコンパイルするときに、コンパイル時の演算子が実行時の演算子と同じように動作することをコンパイラが保証していることを確認してください。

異なる動作の例は、浮動小数点数で見つけることができます。int にキャストし直す場合、コンパイラは単精度、倍精度、または拡張精度で定数式の計算を行っていますか? そのような

constexpr int a = 41;
constexpr int b = (a / 7.5);

私が言いたいのは、非常に多くの異なるアーキテクチャで作業している場合、コンパイラが実行時とコンパイル時と同じ動作を保証することを確認する必要があるということです。

コンパイラが内部的に符号拡張する可能性がありますが、ターゲットで意図したオペコードを生成しない可能性は十分にあります。確認する唯一の方法は、実行時にテストするか、アセンブリの出力を確認することです。

アセンブリ出力を見るのは世界の終わりではありません...いくつの異なるプラットフォームがありますか? これは非常にパフォーマンスが重要なので、5 つの異なるアーキテクチャのアセンブラ出力の 1 ~ 3 行を調べる「作業」を行うだけです。行を見つけるために、(通常は!) アセンブリ出力全体を調べなければならないわけではありません。やり方はとても簡単です。

于 2012-09-17T17:53:48.253 に答える