4

私は誰かの宿題を手伝っていて、この奇妙な問題に遭遇しました。問題は、符号付き整数のバイトの順序を逆にする関数を作成することです (とにかく関数が指定された方法です)。これが私が思いついた解決策です:

int reverse(int x)
{
    int reversed = 0;

    reversed = (x & (0xFF << 24)) >> 24;
    reversed |= (x & (0xFF << 16)) >> 8;
    reversed |= (x & (0xFF << 8)) << 8;
    reversed |= (x & 0xFF) << 24;

    return reversed;
}

この関数に渡す0xFF000000と、最初の代入は になり0xFFFFFFFFます。何が起こっているのかよくわかりませんが、署名付きと未署名の間の変換、またはそのようなものと関係があることは知っています。

追加ulすると正常に0xFF動作します。これは、強制的に署名なしに変換されてから、署名付きまたはその方向の何かに変換されるためだと思います。結果のコードも変更されます。指定子がないul場合は sar(算術右シフト) を使用しますが、符号なしでは意図したとおりに shr を使用します。

誰かが私のためにこれに光を当てることができれば、本当に感謝しています。私はこのことを知っているはずであり、知っていると思っていましたが、ここで何が起こっているのか本当にわかりません.

前もって感謝します!

4

6 に答える 6

12

x符号付きの数量であるため、結果は(x & (0xFF << 24))0xFF000000 であり、これも符号付きであり、最上位 (符号) ビットが設定されているため負の数です。>>演算子 on (符号付きのint値) は符号拡張を実行し(編集: この動作は未定義で実装固有ですが)、値が右にシフトされるときに符号ビット値 1 を伝播します。

符号なしの値のみを処理するには、関数を次のように書き直す必要があります。

unsigned reverse(unsigned x)
{
    unsigned int reversed = 0;

    reversed = (x & (0xFF << 24)) >> 24;
    reversed |= (x & (0xFF << 16)) >> 8;
    reversed |= (x & (0xFF << 8)) << 8;
    reversed |= (x & 0xFF) << 24;

    return reversed;
}
于 2010-09-21T18:30:42.993 に答える
7

結果から、32 ビット マシンを使用していると推測できます。

(x & (0xFF << 24)) >> 24

この式0xFFでは でありint0xFF << 24も でありint、そのまま ですx

&bitwise between twoを実行するintと、結果も にintなります。この場合、値は です0xFF000000。これは、32 ビット マシンでは符号ビットが設定されていることを意味するため、負の数になります。

負の値を持つ符号付き型のオブジェクトで右シフトを実行した結果は、実装定義です。あなたの場合、符号保存算術右シフトが実行されます。

符号なしの型を右シフトすると、バイト反転関数に期待していた結果が得られます。&これは、ビットごとのオペランドのいずれかのオペランドを符号なしの型にして、両方のオペランドを符号なしの型に強制的に変換することで実現できます。(これは、ほぼすべての実装intである an の正の値のすべての可能な範囲をsigned が保持できない実装に当てはまります。)unsigned int

于 2010-09-21T18:38:01.687 に答える
3

符号付き型の右シフトは実装定義です。特に、コンパイラは自由に算術シフトまたは論理シフトを行うことができます。これは、扱っている具体的な値が正の場合は気付かないことですが、負の値になるとすぐに罠に陥る可能性があります。

これは移植性がありません。

于 2010-09-21T18:39:15.757 に答える
1

xは署名されているため、符号には最上位ビットが使用されます。0xFF000000 は「負の 0x7F000000」を意味します。シフトを行うと、結果は「符号拡張」されます。右にシフトされた以前の MSB を置き換えるために左側に追加される 2 進数は、値の符号と常に同じです。そう

0xFF000000 >> 1 == 0xFF800000
0xFF000000 >> 2 == 0xFFC00000
0xFF000000 >> 3 == 0xFFE00000
0xFF000000 >> 4 == 0xFFF00000

シフトされる値が符号なしの場合、またはシフトが左方向の場合、新しいビットは 0 になります。符号拡張が機能するのは、符号付き値の右シフトのみです。

于 2010-09-21T18:33:48.317 に答える
1

符号付き整数と符号なし整数の両方を使用するすべてのプラットフォームで同じように動作させたい場合は、

(x & (0xFF << 24)) >> 24

の中へ

(x >> 24) & 0xFF
于 2010-10-06T20:54:58.067 に答える
0

これがJavaコードの場合は、符号なしの右シフトである「> >>」を使用する必要があります。それ以外の場合は、値を符号拡張します。

于 2010-09-21T19:02:14.573 に答える