1. 兩種不同模式下的整形溢出 坑了個爹的,書上說的沒理解清楚,在Rust程式語言設計中文版3.2中提到了,當使用--release參數進行發佈模式構建時,Rust不會檢測導致panic的整形溢出,這裡需要分兩種情況考慮: 編譯期就可以發現的整形溢出 程式運行過程中會發生的整形溢出 1.1 編譯階段 ...
1. 兩種不同模式下的整形溢出
坑了個爹的,書上說的沒理解清楚,在Rust程式語言設計中文版3.2中提到了,當使用--release參數進行發佈模式構建時,Rust不會檢測導致panic的整形溢出,這裡需要分兩種情況考慮:
- 編譯期就可以發現的整形溢出
- 程式運行過程中會發生的整形溢出
1.1 編譯階段
如果是編譯期能夠確定會發生的整形溢出(程式1-1),無論是不是執行了--release
參數都會在構建階段(cargo build
)發生報錯
// 程式1-1
fn main() {
let i:u8 = 254;
let i = i + 4;
println!("{}!",i);
}
上述變數i
的類型為u8
類型,值的範圍在(0..=255)
,
經過運算的結果最終的i
的值為258
,這個值在編譯期已經可以檢測到整形溢出,最終構建會報錯如下:
-
debug
模式 -
release
模式這種編譯期可以確定的溢出錯誤,兩種模式下都會發生崩潰
1.2 運行階段
在運行期發生的整形溢出(程式1-2),不會在build階段報錯
// 程式1-2
fn main() {
let i:u8 = 254;
for j in 0..=4 {
println!("{}!",i+j);
}
}
上述代碼,只有在j>1
的情況下才會發生整形溢出,這種錯誤在編譯期是發現不了的
-
debug
模式執行在不使用
--release
的時候,在運行階段報錯 -
release
模式在使用
--release
的情況下,溢出值對256進行了取模運算
1.3 說明
當使用--release
進行構建發佈模式時,當檢測到整形溢出,將會使用一種進位補碼包裹(two’s complement wrapping)的操作。就是最終的計算出來的結果對2N取模。N
為類型的bit位,u8是8位,N=8
2 Rust對溢出的操作
摘自:數據類型 - Rust 程式設計語言 中文版 (rustwiki.org)
要顯式處理溢出的可能性,可以使用標準庫針對原始數字類型提供的以下一系列方法:
- 使用
wrapping_*
方法在所有模式下進行包裹,例如wrapping_add
- 如果使用
checked_*
方法時發生溢出,則返回None
值- 使用
overflowing_*
方法返回該值和一個指示是否存在溢出的布爾值- 使用
saturating_*
方法使值達到最小值或最大值這麼處理,在debug模式下就不會panic
2.1 wrapping_*
當計算結果發生溢出執行取模操作(程式2-1)
// 2-1
fn main() {
let i:u8 = 254;
for j in 2..=4 {
println!("=======================");
println!("i+j={}!",i.wrapping_add(j));
println!("j-i={}!",j.wrapping_sub(i));
println!("j*i={}!",j.wrapping_mul(i));
println!("j/i={}!",j.wrapping_div(i));
}
}
結果如下:
那麼問題來了,負數怎麼取整?