2016-04-27 11 views
8

私はこの例を見つけました。誰でもここで何が起こっているのか説明できますか?私はLLVM 7.1を使用しています。Cビットシフトの振る舞い

uint8_t a = 0xff; 
a = ~a >> 1; 
// a = 0b1000000 

uint8_t b = 0xff; 
b = ~b; 
b = b >> 1; 
//b = 0 

abは等しくなければなりません?

EDIT: 追加解体:最初のケース~a

testt`main: 
    0x100000f70 <+0>: pushq %rbp 
    0x100000f71 <+1>: movq %rsp, %rbp 
    0x100000f74 <+4>: xorl %eax, %eax 
    0x100000f76 <+6>: movl $0x0, -0x4(%rbp) 
    0x100000f7d <+13>: movl %edi, -0x8(%rbp) 
    0x100000f80 <+16>: movq %rsi, -0x10(%rbp) 
    0x100000f84 <+20>: movb $-0x1, -0x11(%rbp) 
    0x100000f88 <+24>: movzbl -0x11(%rbp), %edi 
    0x100000f8c <+28>: xorl $-0x1, %edi 
    0x100000f8f <+31>: sarl $0x1, %edi 
    0x100000f92 <+34>: movb %dil, %cl 
    0x100000f95 <+37>: movb %cl, -0x11(%rbp) 
    0x100000f98 <+40>: movb $-0x1, -0x12(%rbp) 
    0x100000f9c <+44>: movzbl -0x12(%rbp), %edi 
    0x100000fa0 <+48>: xorl $-0x1, %edi 
    0x100000fa3 <+51>: movb %dil, %cl 
    0x100000fa6 <+54>: movb %cl, -0x12(%rbp) 
    0x100000fa9 <+57>: movzbl -0x12(%rbp), %edi 
    0x100000fad <+61>: sarl $0x1, %edi 
    0x100000fb0 <+64>: movb %dil, %cl 
    0x100000fb3 <+67>: movb %cl, -0x12(%rbp) 
    0x100000fb6 <+70>: popq %rbp 
    0x100000fb7 <+71>: retq 
+1

いいえ、それらはない_should_。実装定義の動作。十分な情報が与えられていない。アセンブラの出力を見てください。 – Olaf

+0

'aとbは等しい必要があります'なぜですか?コードは異なります。 –

+0

@Olaf:なぜ実装は難しいのですか?符号なし整数の右シフトは確かにうまくいきますか?もしそれが署名されていれば、それはUBになります。 – Jimbo

答えて

10

intに昇格されているので、あなたが得る:

0x80に切り捨てられ
a = 0xffffff00 >> 1 = 0x7fffff80 

。第2のケースで

あなたが得るので、切り捨ては、前にシフトを発生します。

b = 0xffffff00 

0x00に切り捨てられ、その後、これをシフトすること0x00の結果を与えます。

(注:上記の32ビットのintを想定し、通常2Sが表現と符号付きの値の論理右シフトを補完)

+1

32ビットの 'int'(可能)と2の補数(可能性)のためだけです。また、 '〜a'は宣伝されていませんが' a'です。 '〜'はすでに 'int'に対して実行されています。 – Olaf

+0

ありがとう@Olaf - このエフェクトにノートを追加します。 –

+2

うわー、かなり印象づけて、感謝:) – iCaramba