0.8.0版本开始,算术运算有两个计算模式,一个是“wrapping”(截断)模式或为“unchecked”(不检查)模式,即在发生溢出的情况下会进行“截断”,不会触发失败异常,从而得靠引入额外的检查库来解决这个问题(如OpenZeppelin中的SafeMath库);另一个是"checked"(检查)模式。默认情况下,算术运算使用的是“checked”模式,会进行溢出检查,如果结果溢出,会出现失败异常回退。
举个栗子:
uint8最大值为255,255加上一个大于0的整数会溢出,加上unchecked{}会不检查是否溢出,否则默认使用截断模式检查溢出。
- // SPDX-License-Identifier: MIT
- pragma solidity ^0.8.7;
-
- /// @dev 示例合约:uint8最大值为255,255加上一个大于0的整数会溢出,加上unchecked不会检查是否溢出
- contract TestUncheck {
- /// @dev 检查溢出(checked模式)
- function withoutUnchecked() external pure returns (uint8) {
- uint8 a = 255;
- uint8 b = 5;
- return (a + b);
- }
-
- /// @dev 不检查溢出(unchecked模式或称为截断模式)
- function withUnchecked() external pure returns (uint8) {
- uint8 a = 255;
- uint8 b = 5;
- // 不检查溢出,输出溢出结果
- unchecked {
- return (a + b);
- }
- }
- }
检查模式,由于数据溢出,发生异常回退。

截断模式,虽然255+5溢出了,但输出了溢出结果4。

unchecked代码块可以在代码块中的任何位置使用,但不可以替代整个函数代码块,同样不可以嵌套。此设置仅影响语法上位于
unchecked块内的语句。 在块中调用的函数不会此影响。
0.8.0之前版本为“wrapping”(截断)模式,即在发生溢出的情况下会进行“截断”,不会触发失败异常,从而得靠引入额外的检查库来解决这个问题(如OpenZeppelin中的SafeMath库)
测试一个离0.8.0最近版本0.7.6,合约代码如下:
- // SPDX-License-Identifier: MIT
- pragma solidity ^0.7.6;
-
- /// @dev 测试0.8.0以前版本,溢出为截断模式
- contract TestOverflow {
- /// @dev 不检查溢出(wrapping模式)
- function overflow() external pure returns (uint8) {
- uint8 a = 255;
- uint8 b = 5;
- return (a + b);
- }
- }
输出截断数据,即为不检查模式
