2017-10-13 130 views
0

我已經問過類似的問題,但更多的研究後,我碰到的東西來到我無法理解,並希望有人能解釋一下是什麼導致了這種現象:如何正確截斷整型

// We wish to store a integral type, in this case 2 bytes long. 
signed short Short = -390; 

// In this case, signed short is required to be 2 bytes: 
assert(sizeof(Short) == 2); 

cout << "Short: " << Short << endl; // output: -390 

signed long long Long = Short; 

// in this case, signed long long is required to be 8 bytes long 
assert(sizeof(Long) == 8); 

cout << "Long: " << Long << endl; // output: -390 

// enough bytes to store the signed short: 
unsigned char Bytes[sizeof(Short)]; 

// Store Long in the byte array: 
for (unsigned int i = 0; i < sizeof(Short); ++i) 
    Bytes[i] = (Long >> (i * 8)) & 0xff; 

// Read the value from the byte array: 
signed long long Long2 = (Bytes[0] << 0) + (Bytes[1] << 8); 

cout << Long2 << endl; // output: 65146 

signed short Short2 = static_cast<signed short>(Long2); 

cout << Short2 << endl; // output: -390 

輸出:

-390 
-390 
65146 
-390 

有人可以解釋這裏發生了什麼嗎?這是不確定的行爲?爲什麼?

+0

在形式上,程序的行爲是未指定的(最多也可能是未定義的),因爲它依賴於整數的確切表示,這是一個實現細節。實際上,假設典型的二進制補碼錶示法,你正在丟失符號擴展名:'Long2'在高位字節中有零,其中'Long'具有'0xFF' –

+0

@IgorTandetnik我用這種方式存儲整數的原因是,我在某處讀到這是安全地這樣做的方式。我猜這個來源不是很好?你能否詳細說明如何正確地將整數存儲到字節數組中?還是我需要定義我自己的格式? –

+0

Long >> 8','Long'爲負,是實現定義的行爲。 – aschepler

回答

1

這與負數的存儲方式有關。負數將以其二進制格式的1開頭。

signed long long Long = Short; 

這是自動爲您做轉換。它不僅分配一個位到另一個位,而且將從64位值開始的值轉換爲1,以表示負值,其餘值表示390的二進制補碼(不能打擾全部工作出位)。

signed long long Long2 = (Bytes[0] << 0) + (Bytes[1] << 8); 

現在你只是檢索結束的兩個字節,這將只是390的幅度。你的前兩個字節將是零,所以它認爲它是一個正數。它應該作爲2^16 - 390,它確實如此。

signed short Short2 = static_cast<signed short>(Long2); 

這是溢出。 65146不適合帶符號的2字節整數,因此結束填充簽名位,使其解釋爲負數。不共發生,它代表的負數是-390。

+0

這很有道理,謝謝你的解釋! –