"检查"和"不检查"的算术指的是如何处理算术运算(如加法、减法、乘法等)过程中的上溢和下溢问题。
上溢发生在结果超出了变量类型能表示的最大值时,而下溢发生在结果低于变量类型能表示的最小值时。
在Solidity 0.8.0之前,合约开发者需要手动检查这些条件以防止上溢和下溢。
然而,从Solidity 0.8.0开始,默认情况下所有的算术运算都是"检查的"(checked),这意味着如果运算导致上溢或下溢,合约会自动抛出一个错误,阻止不安全的运算。
检查的算术
当算术运算是"检查的"时,Solidity编译器会自动在运算中插入上溢和下溢的检查。
如果任何算术运算尝试超出其类型的范围(无论是上溢还是下溢),合约会抛出错误,并回滚交易。
这提高了合约的安全性,因为它防止了无意间引入因上溢或下溢导致的安全漏洞。
不检查的算术
如果你出于性能考虑或其他原因,希望在某些情况下避免上溢和下溢的自动检查,可以使用unchecked代码块。
在unchecked块中,Solidity不会自动检查算术运算的上溢和下溢。
如果运算结果超出变量类型的范围,将不会抛出错误,而是会"环绕"(wrap around),这意味着计算结果会从类型的最小值开始重新计算。
使用unchecked需要非常小心,因为它可能导致不期望的行为和安全漏洞。
你应该只在完全理解可能的后果,并且确实需要避免检查开销时,才使用它。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract CheckedArithmetic {
// 由于Solidity 0.8.0及以上版本,默认所有算术运算都是"检查的",
function add(uint8 a, uint8 b) public pure returns (uint8) {
return a + b; // 如果a + b上溢,将抛出错误
}
// 关闭检查
function add2(uint8 a, uint8 b) public pure returns (uint8) {
unchecked {
// 举个例子,分别赋值为250和10。
// 250 + 10 = 260
// 260 % 256 = 4 因为uint8的范围是0到255,共256个可能的值
// 环绕中,我们只关心余数,因为这代表了超出256个值范围后剩余的部分。因此,250+10在uint8中的"环绕"结果就是4。
return a + b; // 在这里,如果 a + b 超出了 uint8 的范围,结果会发生"环绕"
}
}
}