農林漁牧網

您現在的位置是:首頁 > 農業

技術 | 你不知道的Java——01.資料型別溢位

2021-12-14由 格睿泰思 發表于 農業

移碼運算怎麼避免發生溢位

技術 | 你不知道的Java——01.資料型別溢位

學習JAVA的同學都知道,JAVA有8個基本資料型別。其中除char是無符號資料型別,其餘資料型別均為有符號。

在這些有符號的資料型別中,均存在資料型別溢位的問題。

這個問題的危害其實非常的大,如果它應用於某些計算中,又沒有對資料進行有效驗證,那麼有極大可能讓攻擊者利用並透過這個漏洞做出意想不到的結果。

以下將詳細講解這個漏洞的成因和解決方案

所謂有無符號是指首高位佔位是否表示為正負號,在有符號的資料型別中,

首高位為0時表示負數

,首

高位為1時表示正數

。以

byte型

為例,byte佔2位元組,共16位。當byte的值為1時,其2進製表示為

技術 | 你不知道的Java——01.資料型別溢位

當byte值為-1時

,其正碼錶示為

技術 | 你不知道的Java——01.資料型別溢位

但由於計算規則要求,需要進行

反碼運算

所謂反碼運算是指除首高位(即最左邊第一位)符號位的值不變,其它各位原值為0的表為1原值為1的表為0。因此反碼運算後結果為

技術 | 你不知道的Java——01.資料型別溢位

同時為了讓計算機能夠正確識別和計算,規定在反碼的基礎上進行

補碼

。因此,-1的最終結果為

技術 | 你不知道的Java——01.資料型別溢位

為避免出現-0這樣的無效且冗餘的表示,如:

技術 | 你不知道的Java——01.資料型別溢位

則規定,上述表示為負數最大值+1,即-128。我們不再深入討論為什麼要進行反碼和補碼運算,這將會在另外的篇章中進行,這裡我們只需要記住負數需要反碼和補碼運算就好。接下來我們來看看資料是怎麼溢位的

技術 | 你不知道的Java——01.資料型別溢位

上述程式碼初看並沒有任何問題,我們申明瞭一個byte型的變數,其值為127,給它的值加上1後輸出,但輸出結果我們會發現是-128而非128。

為什麼會這樣?

我們先看看它原值127的2進製表示為

技術 | 你不知道的Java——01.資料型別溢位

那麼,當我們給這個值+1後的結果又會是什麼?在最右邊的尾數上+1,我們發現它會不斷進位,最終形成這樣的結果

技術 | 你不知道的Java——01.資料型別溢位

前面我們講過,在byte的2進製表示中,首高位為1則表示負數。因此,當這個變數+1後正好是我們前面講到的-128

當上述程式碼改成b+2時

,為什麼又成了-127呢?同樣,我們從127的原碼中開始增加,127的2進位制+2會形成如下結果

技術 | 你不知道的Java——01.資料型別溢位

但是注意

,此時的計算機會認為,這個結果已經是反碼和補碼後的結果。在寫出計算時修正結果,進行同樣的反碼補碼運算。注意:這裡在“最後一位減掉再反碼”和“全部反碼後再補碼“的數學計算上都是一樣的

技術 | 你不知道的Java——01.資料型別溢位

因此,最後寫出時計算機會認為它的真值表示為

技術 | 你不知道的Java——01.資料型別溢位

即為-127

我們知道,在JAVA中任何數字預設都表示為

int型

。如果

b+1

的結果不強制轉為

byte

這個結果也會預設為

int

,那麼它並不會出現型別溢位的問題。事實也正是如此,在JAVA中我們很少發現其它型別的溢位,而

int

的溢位漏洞卻經常發現。

Int型

溢位過程與

byte

溢位過程原因一致。為了避免這個漏洞的產生,通常我們採用以下幾種方法驗證參與運算的因子大小,並用更大的資料型別來儲存結果。

例如:

使用者輸入a和b兩個數,驗證a、b兩數的範圍不可大於int型最大值,但用長整形來接收

技術 | 你不知道的Java——01.資料型別溢位

這種方式並不能從根本上解決問題,所以更好的建議是使用

java.util.BigInteger類

來解決。

更多技術乾貨歡迎關注公眾號:scgrts

技術 | 你不知道的Java——01.資料型別溢位

採編寫:左 左