2011-10-13 49 views
1

我一直在試一會包&將一些字符解壓縮爲一個整數。雖然有些話題與這個問題有關,但我的問題與簽名轉變有關。我不明白的「絕招」才能解籤值,即:使用簽名數據按位解包

char c1 = -119; 
char c2 = 26; 

// pack 
int packed = (unsigned char)c1 | (c2 << 8); 
// unpack 
c1 = packed >> 0; 
c2 = packed >> 8; 

// printf(c1, c2) -> Unpacked data: -119 | 26 

這工作正常,但是當我嘗試將更多的數據,即:

char c0 = -42; 
char c1 = -119; 
char c2 = 26; 

// pack 
int packed = (unsigned char)c0 | (unsigned char)(c1 << 8) | (c2 << 16); 
// unpack 
c0 = packed >> 0; 
c1 = packed >> 8; 
c2 = packed >> 16; 

// printf -> Unpacked data: -42 | 0 | 26 

C1值錯過了。我想這與有關,符號位被移入高位

我怎麼能回來c1價值?

在此先感謝。

回答

4

您正在鑄造c1unsigned char後移出該類型的範圍內的,所以鑄件的結果是零。變速前應執行流延:

int packed = (unsigned char)c0 | ((unsigned char)c1 << 8) | (c2 << 16); 
+0

好解釋:)有沒有地方的疑慮。謝謝! – pQB

2
(unsigned char)(c1 << 8) 

這將

  • 移位錯誤(符號擴展)值
  • 結果修整成8位(產生0)

你不想要任何這個,所以你應該使用((unsigned char)c1 << 8)

+0

不真實。無論簽名的類型是多麼寬或很窄,鑄造簽名都是不確定的行爲。 (與鑄造無符號簽署相反)。代碼仍然是錯誤的,但它不是UB。 – Nemo

+0

@Nemo:你說的對,我想知道我在想什麼...... – jpalecek

0

一些int s是16位。對於此代碼是便攜式使用int32_t。正確的方法來做到這一點(雖然有點偏執)是:

int32_t packed = ((uint8_t)c0) | (((uint8_t)c1)<<8) | (((uint8_t)c2) << 16); 

我也傾向於以相反的順序列出這些,所以它是更自然的字符成爲了最高和最低顯著字節。