技術 | 你不知道的Java——01.資料型別溢位
2021-12-14由 格睿泰思 發表于 農業
移碼運算怎麼避免發生溢位
學習JAVA的同學都知道,JAVA有8個基本資料型別。其中除char是無符號資料型別,其餘資料型別均為有符號。
在這些有符號的資料型別中,均存在資料型別溢位的問題。
這個問題的危害其實非常的大,如果它應用於某些計算中,又沒有對資料進行有效驗證,那麼有極大可能讓攻擊者利用並透過這個漏洞做出意想不到的結果。
以下將詳細講解這個漏洞的成因和解決方案
。
所謂有無符號是指首高位佔位是否表示為正負號,在有符號的資料型別中,
首高位為0時表示負數
,首
高位為1時表示正數
。以
byte型
為例,byte佔2位元組,共16位。當byte的值為1時,其2進製表示為
當byte值為-1時
,其正碼錶示為
但由於計算規則要求,需要進行
反碼運算
。
所謂反碼運算是指除首高位(即最左邊第一位)符號位的值不變,其它各位原值為0的表為1原值為1的表為0。因此反碼運算後結果為
同時為了讓計算機能夠正確識別和計算,規定在反碼的基礎上進行
補碼
。因此,-1的最終結果為
為避免出現-0這樣的無效且冗餘的表示,如:
則規定,上述表示為負數最大值+1,即-128。我們不再深入討論為什麼要進行反碼和補碼運算,這將會在另外的篇章中進行,這裡我們只需要記住負數需要反碼和補碼運算就好。接下來我們來看看資料是怎麼溢位的
上述程式碼初看並沒有任何問題,我們申明瞭一個byte型的變數,其值為127,給它的值加上1後輸出,但輸出結果我們會發現是-128而非128。
為什麼會這樣?
我們先看看它原值127的2進製表示為
那麼,當我們給這個值+1後的結果又會是什麼?在最右邊的尾數上+1,我們發現它會不斷進位,最終形成這樣的結果
前面我們講過,在byte的2進製表示中,首高位為1則表示負數。因此,當這個變數+1後正好是我們前面講到的-128
當上述程式碼改成b+2時
,為什麼又成了-127呢?同樣,我們從127的原碼中開始增加,127的2進位制+2會形成如下結果
但是注意
,此時的計算機會認為,這個結果已經是反碼和補碼後的結果。在寫出計算時修正結果,進行同樣的反碼補碼運算。注意:這裡在“最後一位減掉再反碼”和“全部反碼後再補碼“的數學計算上都是一樣的
因此,最後寫出時計算機會認為它的真值表示為
即為-127
我們知道,在JAVA中任何數字預設都表示為
int型
。如果
b+1
的結果不強制轉為
byte
這個結果也會預設為
int
,那麼它並不會出現型別溢位的問題。事實也正是如此,在JAVA中我們很少發現其它型別的溢位,而
int
的溢位漏洞卻經常發現。
Int型
溢位過程與
byte
溢位過程原因一致。為了避免這個漏洞的產生,通常我們採用以下幾種方法驗證參與運算的因子大小,並用更大的資料型別來儲存結果。
例如:
使用者輸入a和b兩個數,驗證a、b兩數的範圍不可大於int型最大值,但用長整形來接收
這種方式並不能從根本上解決問題,所以更好的建議是使用
java.util.BigInteger類
來解決。
更多技術乾貨歡迎關注公眾號:scgrts
採編寫:左 左