2017-09-26 104 views
4

的,我注意到一些奇怪的行爲與支架Bitshifts抵消,而不是預期的行爲

bitshifting
#include <stdio.h> 

int  main(void) 
{ 
    unsigned char c; 
    unsigned char d; 

    c = 153; 
    c = (c << 7) >> 7; 
    printf("%d\n", c); 
    d = 153; 
    d = (d << 7); 
    d = (d >> 7); 
    printf("%d\n", d); 
} 

輸出:

153 
1 

我預計c也有1 ...值怎麼回事上?這是不確定的?

+2

看看生成的代碼以及它的功能。 –

+1

與[this]類似(https://stackoverflow.com/questions/33068985/sizeof-an-integer-expression-in-c)問題。表達式被評估爲一個整數,然後存儲爲char。與中間步驟中的字符對比。 – matt

+0

沒問題,lemmi只能使用類型轉換 –

回答

4

位移char自動將其升級到int。這就是爲什麼7位左移不能切斷任何東西。

來源:the C standard

部6.5.7整數優惠在每個操作數的執行。結果的類型是 升級左操作數的類型。如果右操作數的值爲負或大於或等於提升的左操作數的寬度,則行爲未定義。

+1

不錯的答案,比我快,+ 1 – gsamaras

+0

耶謝謝。我現在也選擇使用'c =(unsigned char)(c << 7) >> 7;'它給了我預期的輸出 –

2

它被評估爲int,然後存儲爲char。並且在中間步驟不是char。換句話說,當你移位char時,它會被提升爲int

檢查什麼標準6.5.7 Bitwise shift operators有說:

  • 的整數促銷活動在每個操作數的執行。

  • 結果的類型是提升的左操作數的類型。

  • 如果右操作數的值爲負或大於或等於提升的左操作數的寬度,則行爲爲 未定義。

0

按照什麼this comment表明,我們來看看這是對平臺的x86生成表達c = (c << 7) >> 7代碼:

movzbl 31(%esp), %eax ;eax = c 
sall $7, %eax ;left shift 
sarl $7, %eax ;right shift 
movb %al, 31(%esp) ;c = al (one byte) 

c內容被加載到32 (eax),並且這兩個移位都在該寄存器上執行。最後,該寄存器的最低有效字節(即al)被分配給變量c

簡而言之,兩個移位都被評估爲操作數是32位寬。

1

根據this online c standard draft,按位移位運算促進參數爲整數類型:

6.5。7位移位運算符

2每個操作數應具有整數類型。

3對每個操作數執行整數提升。

所以當你寫c = (c << 7) >> 7,的c在表達(c << 7)的值首先被轉換爲一個整數值,然後移動。因此,沒有一點會迷失。將它們移回>> 7給出原始值。

當您編寫d = (d << 7)時,相反,一旦將(積分)結果重新分配給d(這是一個無符號字符並且因此無法保持整數值的「高位」位),位會丟失。

1

153 in binary representation is 10011001。按位移操作符的操作數應該有int類型,否則將發生整數提升。

For語句

c = (c << 7) >> 7; 

c被促進爲整數,並假設爲整數表示4個字節,c00000000 00000000 00000000 10011001二進制。所以表達式

c = (c << 7) >> 7; // Left and right shift operator will nullify the effect of each other. 

將有表達

c = c; 

的效果在

d = (d << 7); 
d = (d >> 7); 

情況下,第一條語句d後會有值(二進制)10000000。在第二個陳述後d將有值(二進制)00000001