上溢後,結果為什麼可以用 (原值%對應數據類型最大值) 求出?

有點不理解,求解答。


uint16_t value; // & 即題目中的 16 位的 unsigned short

value = 100000;

「理應」發生什麼:

首先是賦值:整型間的賦值屬於「簡單賦值」,簡單賦值的規則是「將右側的值轉換為左側的類型,然後替換左側的對象」。

其次是右側「100000」的類型:沒有後綴的十進位數值常量的類型是 int、long、long long 中第一個能夠表示這個值的類型。是那個得看具體的系統,反正不是 uint16_t 就是了。

最後是類型轉換,C 語言標準中描述的規則是這樣的:

  1. 如果新類型可以表示原值,直接保留該值;
  2. 否則,如果新類型是無符號的,則將原值不斷加上後者減去「新類型的最大值加 1」,直到可以被新類型表示為止
  3. 否則,如果新類型是有符號的,由具體實現覺得其行為。

代入此處可以看到

  1. 100000 無法被 uint16_t 表示,因為表示範圍為 [0, 65535];
  2. 100000 大於 65535,於是按照規則減去 65535 + 1 得到 34464,可以被 uint64_t 表示,於是得到最終的值,賦予 value。

---

那麼該如何理解題目里的說法呢?

編譯器對其二進位表示截取低 16 位,相當於對 65536 求余,得到 34464

回顧小學數學,「餘數」是什麼?

當兩個整數相除的結果不能以整數商表示時,餘數便是其「余留下的量」。

回顧小學數學,「除法」是什麼?

重複的減法

所以「X 對 65536 求余」換句話說就是

將 X 不斷減去 65536,直到剩下的值在 [0, 65535] 的範圍內

這和上面提到的標準里所說的

將原值不斷加上或者減去「新類型的最大值加 1」,直到可以被新類型表示為止

是一樣的。

---

至於為什麼「對其二進位表示截取低 16 位」相當於「對 65536 求余」:

如果把數 X 的低 16 位記為 L,其餘高位記為 H,那麼可以得到:

X = H 	imes 2^{16}  + L 	imes  2^{0}

「截取低 16 位」後則為:

= X - H 	imes 2^{16} = X - H 	imes 65536

你看,還是「將 X 不斷減去 65536」,而且是有多少個就減多少個……


推薦閱讀:

在Visual Studio開發c++程序時,怎樣使用和管理第三方的開源庫?
C++項目怎麼適用不同的linux系統?
請問float的最大值是怎麼來的?
寫程序時中間變數用cnm,是什麼心態?
這一段 C++ 代碼有什麼樣的問題?

TAG:編程語言 | C編程語言 | C | CC | CPrimer |