2011-09-04 46 views
0

這裏的存儲方式是我用的程序:測試機器

int hex = 0x23456789; 
char * val = &hex; 
printf("%p\n",hex); 
printf("%p %p %p %p\n",*val,*(val+1),*(val+2),*(val+3)); 

這裏是我的輸出:

0x23456789 
0xffffff89 0x67 0x45 0x23 

我是一個64位CPU,64位操作系統上運行。這表明我的機器是小端的。爲什麼是第一個字節0xffffff89?爲什麼是ff?

回答

5

首先,你應該使用%x,因爲這些不是指針。

%x指定符需要一個整數。因爲您正在傳入一個類型爲'char'的值,該值是一個有符號類型,所以該值將被轉換爲一個整數並進行符號擴展。 http://en.wikipedia.org/wiki/Sign_extension

這基本上意味着它佔用最重要的位並將其用於所有更高位。因此0x89 => 0b10001001,其中最高位'1'變爲0xFFFFFF89。

正確的解決方案是指定一個'長度'參數選項。您可以在此處獲得更多信息:Printf Placeholders基本上,在'%'和'x'之間,您可以放置​​額外的參數。 'hh'表示您正在傳遞一個char值。

int hex = 0x23456789; 
char *val = (char*)&hex; 

printf("%x\n",hex); 
printf("%hhx %hhx %hhx %hhx\n", val[0], val[1], val[2], val[3]); 
+1

'「%p」'期望一個'void *',而不是一個整數。任何指針都可以在大多數機器上工作,但在技術上是正確的(因爲可變參數),所以在使用它時應該明確地施放。 –

+0

好點。我剛剛刪除提及它。 – loganfsmyth

+1

此外,您需要使用'「%hhx」'來打印一個'unsigned char'值,而不是一個完整的'unsigned'值。 –

2

%p被詢問printf to format it as an address,你actaully傳遞的值(* VAL)

在64位機器上的指針的地址是64位,所以printf的被添加FFFF到墊的字段

+0

爲什麼不爲其他值做它?如0xffffff67。我使用%x代替%p,並得到相同的輸出。 – Bruce

+0

這是未定義的行爲,您要求它將地址打印爲不是地址的值。所以它可能會使用堆棧中的下一個值,或者它可能會打印粉紅色的獨角獸 –

+0

爲什麼輸出與%x相同? – Bruce

3

char是一個有符號類型,它在作爲參數傳遞時被提升爲int。此促銷活動會延長簽名。 0x89是char的負值,因此它會被符號擴展爲0xffffff89。對於其他值不會發生這種情況,它們在大多數機器上不超過CHAR_MAX,127或0x7f。由於您使用了錯誤的格式說明符,您會對此行爲感到困惑。

1

正如@馬丁貝克特說,%pprintf要求打印指針,這相當於%#x%#lx(確切的格式取決於你的OS上)。

這意味着printf期待一個intlong(再次取決於操作系統),但你只用char提供這麼值向上強制轉換爲適當的類型。

當你施放一個小籤號碼你必須做一些所謂的sign extension爲了保值,一個更大的符號數。在0x89的情況下,會發生這種情況是因爲符號位已設置,所以高位字節爲0xff,因爲它們很重要而被打印出來。

0x67,0x45,0x23的情況下,符號擴展不會發生,因爲符號位未設置,因此高位字節爲0,因此不會打印。

1

我測試字節序與條件((char)((int)511) == (char)255)。真的意味着小,虛假意味着大。

我已經在幾個不同的系統,既少,大與優化關閉,以最大測試這一點,使用gcc。在我做的每一個測試中,我都得到了正確的結果。

在需要執行關鍵操作之前,可以將該條件放入應用程序中。如果你只想機制保障您正在使用正確的字節序爲您的整個應用程序,你也可以使用一個靜態斷言方法如如下:

extern char ASSERTION__LITTLE_ENDIAN[((char)((int)511) == (char)255)?1:-1]; 

在全球範圍內這條線將創建一個編譯錯誤,如果該系統不是小端,並會拒絕編譯。如果沒有錯誤,它就會完美編譯,就好像該行不存在一樣。我發現該錯誤消息是相當描述:

error: size of array 'ASSERTION__LITTLE_ENDIAN' is negative 

現在,如果你是偏執狂你的編譯器優化了實際的檢查走像我的,你可以做到以下幾點:

int endian; 
{ 
    int i = 255; 
    char * c = &i; 
    endian = (c[0] == (char)255); 
} 
if(endian) // if endian is little 

它壓縮在很好地對這個宏:

#define isLittleEndian(e) int e; { int i = 255; char * c = &i; e = (c[0] == (char)255); } 
isLittleEndian(endian); 
if(endian) // if endian is little 

或者,如果你使用GCC,你可以逃脫:

#define isLittleEndian ({int i = 255; char * c = &i; (c[0] == (char)255);}) 
if(isLittleEndian) // if endian is little 
+0

你能解釋你答案的第一行嗎? –