2014-05-02 172 views
0

我目前正在C中嘗試按位操作,我試圖理解爲什麼此代碼爲變量a和變量b打印不同的值。 我知道32位移位溢出1變量(這是一個正常的int),但我的理解是,它應該在兩種情況下打印0。C按位操作的行爲

取而代之的是,它使用unsigned int aunsigned long int b來打印一個隨機數。

#include <stdio.h> 

int main(){ 
    printf("%lu %lu\n",sizeof(int), sizeof(long int)); 
    unsigned int a = 1 << 32; 
    unsigned long int b = 1 << 32; 
    printf("%u %lu\n", a, b); 
    return 0; 
} 

輸出示例:

4 8 
374588997 0 

我缺少什麼?

編輯

現在我有一個31位的移位只是想,編譯器給了我沒有警告。 來源:

#include <stdio.h> 

int main(){ 
    int shift = 31; 
    unsigned long int b = 1 << shift; 
    printf("%lu\n", b); 
    return 0; 
} 

,並將其輸出18446744071562067968,那真的不是2^31。任何線索?

+2

如果是[未定義行爲是移位大小大於或等於位長度](https://stackoverflow.com/questions/19636539/arithmetic-right-shift-gives-bogus-result/19636588 #19636588)。 –

+0

好的,但爲什麼它會在兩個操作之間給出不同的結果?表達仍然是相同的:1 << 32,LHS改變但表達式應該已經被評估。 –

+0

因爲鼻子惡魔。 http://www.catb.org/jargon/html/N/nasal-demons.html – thejh

回答

0

更改您的代碼如下

#include <stdio.h> 

int main(){ 
    int shift = 31; 
    unsigned long int b = 1LU << shift; /* or 1U << shift */ 
    printf("%lu\n", b); 
    return 0; 
} 

看來您的系統long int類型爲64位。

你正在得到int結果是負數,並試圖將其存儲到64位無符號導致奇數。

p.s. 18446744071562067968 = FFFFFFFF80000000

+0

@ShafikYaghmour謝謝你的專家評論。你能否提出更多的解釋,爲什麼它沒有定義?我已經閱讀了許多知識分享帖子。這裏的一個簡短的評論/解釋會讓OP和我都受益。 –

+0

你對問題的解釋是不完整的,我在我的[comment above]中鏈接了一個解釋(http://stackoverflow.com/questions/23424985/behavior-with-c-bitwise-operations/23425138#comment35898968_23424985)。你的示例代碼是可以的,因爲你只是通過'31'移動,但你需要解釋未定義行爲的結果是不可靠的,儘管它們可以在特定實例上解釋,但它不是一般性解釋。 –

+0

請注意,'clang'會爲OPs代碼生成一些有用的錯誤消息,請使用以下標誌查看[實例](http://coliru.stacked-crooked.com/a/5af1d78f92469aef):'-Wall -Wextra - Wconversion -pedantic -sanitize = undefined'。 –

-1

您的代碼按照我的預期工作(gcc 4.6.3在12.04LTS上)。但它會產生一些關於移位數大於類型寬度的警告。

編纂得出:運行

Test.c: In function ‘main’:

Test.c:5:5: warning: left shift count >= width of type [enabled by default]

Test.c:6:4: warning: left shift count >= width of type [enabled by default]

輸出:

4 8

0 0

祝你好運!

0

第一個a是隨機的,因爲移位數大於該類型的長度。這是未定義的行爲:

/tmp/test.c: In function 'main': 
/tmp/test.c:5:6: warning: left shift count >= width of type [enabled by default] 
     unsigned int a = 1 << 32; 
    ^

現在b被聲明爲long int,但其值被默認1計算與32位邏輯,由於是int

/tmp/test.c:6:8: warning: left shift count >= width of type [enabled by default] 
     unsigned long int b = 1 << 32; 
    ^

對於b的正確表達。將:

unsigned long int b = 1L << 32; 

編輯回答您的新問題:

在C中,1默認爲signed int因此1 << 31是負數-2147483648。現在這個數字被轉換爲64位,它變成0xffffffff80000000(-2147483648作爲帶符號的long int),最終它的符號被丟棄。這就是爲什麼你得到18446744071562067968這是0xffffffff80000000。

+0

如果我改變B'的'的聲明如'unsigned long int類型B = 1L << 32;',第二誤差消失,我得到的輸出: '4 8' '0 4294967296' –

+0

因爲4294967296是0b100000000000000000000000000000000,你很好:) – Grapsus