2016-09-13 5 views
2

連鎖ビットシフト演算が連鎖しないのと同じ結果を返さない理由がわかりません。Cでビットシフト演算子を連鎖した後に予期しない結果が発生しました

#include <stdio.h> 

void bit_manip_func(unsigned char byte) 
{ 
    unsigned char chain = (((byte >> 3) << 7) >> 3); 
    printf("%d\n", chain); //this prints 144 

    unsigned char o1 = byte >> 3; 
    unsigned char o2 = o1 << 7; 
    unsigned char o3 = o2 >> 3; 
    printf("%d\n", o3); //this prints 16 as expected 
} 

int main() 
{ 
    //expecting both printf's to print 
    //the same value (16). 
    bit_manip_func(73); 
    return 0; 
} 

私はバイナリで73以来、16をプリントアウトするために、両方のprintf呼び出しを期待していは0100 1001ですbyte >> 3を適用した後、私は0000 1001を取得する必要があり、(byte >> 3) << 7後に結果を1000 0000であるべきであり、(((byte >> 3) << 7) >> 3)後の結果がすべき0001 0000、もちろん16です。実際に何が起こっていますか?

unsigned char chain = (((byte >> 3) << 7) >> 3); 

((byte >> 3) << 7)

+6

[整数プロモーション](http://www.idryman.org/blog/2012/11/21/整数昇進/)、毎回このような質問が尋ねられます。 – Groo

+0

かもしれませんが、整数昇格とは何の関係もありませんでした。 – cuvidk

+0

'int'はCの特別な型であり、計算の間にすべての小さな型が' int'に昇格することを覚えておくことが重要なルールです。 16ビットアーキテクチャ( 'int'は16ビット幅)用にコンパイルされたソースコードは、32ビット用にコンパイルされたときの動作が異なります。 – Groo

答えて

5

演算子>>および< <は、オペランドで整数昇格を実行します。したがって、unsigned char型はどちらの演算子でも使用されるとint型に昇格します。次の行で

、可変バイトがint型に昇格され、その後、3つの全ての操作は、このタイプで実行される:

unsigned char chain = (((byte >> 3) << 7) >> 3); 

いずれかに設定左端のビットは、このように保存される。

01001001 => 01001 => 010010000000 => 010010000 
^   ^ ^   ^

以下のコードでは、変数はint型に昇格されますが、各演算の後にint型の結果が符号なしのcharに割り当てられてラップされます(最上位ビットが削除されます)
tあなたのプラットフォームでは、unsigned charの範囲は[0、2^8-1]です。

unsigned char o1 = byte >> 3; 
unsigned char o2 = o1 << 7; 
unsigned char o3 = o2 >> 3; 

これが1に設定左端のビットが保存されていないことを意味する:

01001001 => 01001 => 10000000 => 000010000 
^   ^  
+1

この説明はかなり素晴らしいです – cuvidk

+0

@cuvidkありがとう、私はお試しください。 – 2501

2

は、それはあなたが= 144

((73 >> 3) << 7) >> 3) % 256使用キャストを取得unsigned char(MOD 256)に包まれたint

オーバー>> 3行い、intに昇格されます:

unsigned char chain = ((unsigned char)((byte >> 3) << 7) >> 3); 
+0

@Downvoter:説明に注意してください。 –

+0

一般的なケースでは、入力 'byte'を' unsigned int'にキャストし、最終結果を 'unsigned char'に明示的にキャストする方が良いでしょう。 'unsigned char'への中間キャストは、可能な限り最上位ビットの損失が意図的である場合にのみ意味を持ちます。これは再びint型に昇格します。操作を分割する方がより明確になります。また、負の整数値を右シフトした結果はインプリメンテーションで定義されているため、ビットシフト演算は常に符号なし整数型の 'unsigned int'またはhigher_のランク付けを行う必要があります。固定幅の ''タイプの余分なポイント。 – sendaran

+1

'(unsigned char)((unsigned int)byte >> 3)<< 7) >> 3))' ?,これは目的の出力ではありません(16)、まだ144 –

関連する問題