2012-06-12 48 views
2

我一直在用C編寫一個程序,將char的前4位移到末尾,最後4位移到開始位置。對於大多數值而言,它的工作原理以及反向操作都是正常的,但對於某些值,如8,x,y,z,它會給出一個32位值。通過打印變量的十六進制值檢查值。有人可以解釋爲什麼會發生這種情況嗎?char上的按位運算產生32位結果

#include <stdio.h> 
#include <stdlib.h> 

int main() 
{ 
    char o, f,a=15; 
    scanf("%c",&o); 
    printf("o= %d\n",o); 
    f=o&a; 
    o=o>>4; 
    printf("o= %d",o); 
    o=o|(f<<4); 
    printf("o= %x, size=%d\n",o,sizeof(o)); 
    f=o&a; 
    o=o>>4; 
    printf("o= %d",o); 
    o=o|(f<<4); 
    printf("o= %x, size=%d\n",o,sizeof(o)); 
    return 0; 
} 
+0

'sizeof(o)'是那些永遠不會改變的東西之一 –

+0

@ K-ballo然而,一致性是一個好習慣;所有其他尺寸都需要這個操作員,所以'o'的類型會改變,它不會給你一個難的時間。 – 2012-06-12 17:44:34

+0

@ H2CO3:我印象中OP正在打印'sizeof(o)'的結果,看看'o'的類型和大小是否改變了。 –

回答

6

傳遞o作爲參數printf()導致自動轉換爲int,這在您的系統上顯然是32位。自動轉換使用符號擴展名,所以如果o中的第7位被設置,轉換結果中的第8-31位將被設置,這將解釋您所看到的內容。

您可以使用unsigned char而不是char來避免這種情況。或者通過o & 0xffprintf()

+0

...或使用'%hhx'。 – caf

+0

@caf:'%hhx'需要一個'unsigned char'參數。該標準似乎使傳遞一個負值未定義的行爲,雖然我不確定這是否意圖。 –

3

嘗試聲明您的變量爲unsigned char。您正在獲取高位的符號擴展名。

+0

對不起,在這個問題中沒有提到這一點,但我已經知道如何解決它。我真正要求的是爲什麼會發生這種情況。不過謝謝你的回答。 – Dumitru

2

作爲printf參數給出的字符(或任何可變參數函數或任何沒有原型的函數)被提升爲int。如果char在您的平臺上簽名並且傳遞的值爲負數,則該符號將被擴展。

2

您的值打印爲32位值,因爲格式說明符%x告訴printf將值打印爲unsigned int。要將其打印爲unsigned char,您需要使用長度修飾符hh的格式說明符%hhx。如果這些值是正值,那麼對於打印的輸出沒有區別,但是對於負值它確實是因爲它們具有最重要的位設置。

以下解釋該代碼中負值如何出現,我假設CHAR_BIT == 8和二進制表示負整數。

對於班次,o的值被提升爲int。如果原始值的第四個最低有效位已設置(如果爲(o & 8) != 0),則在第一次交換半字節之後,將設置最高有效位o。如果char默認在您的平臺上簽名,那意味着結果是否定的。對於第二個半字節交換,o的值再次提升爲int,結果爲負值。負值的右移位是實現定義的,所以

o=o>>4; 

是不可移植在這種情況下(儘管在實踐中,所有實施方式使用任一的算術右移[用符號擴展]或邏輯右移[從左移零])。

在實現上做負整數算術移位的o四個最顯著位都將被設定,所以

o=o|(f<<4); 

不會再更改該值。

要移植代碼以獲得所需行爲的唯一方法是按照Ned的建議,將o聲明爲unsigned char。那麼所有的價值觀都是積極的,而且這些變化的行爲是明確的,並符合您的期望。