可以通过 type(uint256).max; 获取 uint256 的最大值,该值为
115792089237316195423570985008687907853269984665640564039457584007913129639935
即 2²⁵⁶-1。
但使用 type(uint256).max 会更简洁且更安全。
同样的方法也可用于有符号整数类型
//57896044618658097711785492504343953926634992332820282019728792003956564819967
type(int256).max;
//-57896044618658097711785492504343953926634992332820282019728792003956564819968
type(int256).min;
整数和无符号整数最大值背后的数学原理
对于无符号整数,只需在你喜欢的解释型语言终端中输入 2 ** n - 1 即可得到答案,其中 n 是相关 uint 的大小,例如 uint128 或 uint32(甚至是很少使用但有效的尺寸,如 uint208)。uintN 意味着有 N 个比特来表示该数字,当所有这些位都被设置为 1 时,即为其最大二进制表示形式。
EVM 使用补码(Twos Complement)来表示有符号数,因此要获取有符号整数的最大值,公式为 ,最小负数值为 。
获取 uint256 最大值的 Hack 方法
你也可以用十六进制来指定它,这会比使用十进制表示更简洁一点,但仍然占用大量空间且容易出错。
十六进制的 uint256 最大值
0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
整整 64 个“f”,千万别搞错!这里的 64 是由 256 比特除以 8 得到字节数(32),而在十六进制中每个最大字节的表示均为 0xff 推导而来的。
~uint256(0) 等同于 uint256 最大值
uint256 的最大值是 256 个比特全设为 1。所以使用位翻转操作符(`~``)怎么样?
type(uint256).max == ~uint256(0) // this will return true
另一个难看的解决方案是让整数下溢
function maximum() public pure returns(uint256) {
unchecked { return uint256(0) - uint256(1); }
}
以下代码可以正常工作,但它具有欺骗性,不推荐使用
function maxUint() public pure returns (uint256) {
return 2**256 - 1;
}
它会返回正确的值,你可以通过以下方式进行验证:
assert(2**256 - 1 == type(uint256).max);
如果你在 Solidity 中将 2**256 写为常量,代码将无法编译,因为编译器会识别出 2**256 太大而无法装入 uint256 中。但是,如果它紧跟着一个 “- 1”,那么编译器就会识别出该算术运算的结果符合此类型。
uint256(-1) 已经失效
在早期版本的 Solidity 中,可以使用 uint256(-1) 来获取最大值,但这已经无法编译了。
最好还是避开所有这些繁琐的技巧,直接使用 type(uint256).max;
2^256 - 1 到底有多大?
为了给这个数字加上一些背景概念,已知宇宙中原子的估计数量大约是 10^80。为了形象化展示,让我们将这两个数字并排放置:
115792089237316195423570985008687907853269984665640564039457584007913129639935
100000000000000000000000000000000000000000000000000000000000000000000000000000000
这大致意味着 1,000 个 uint256 变量就可以枚举已知宇宙中的每一个原子。由于大多数我们感兴趣的“事物”通常由远超 1,000 个原子组成,因此单个 uint256 就能枚举任何有用的事物集合,并且绰绰有余。
由此推论,在所有实际应用中,随机选取的两个 uint256 值(相当于 keccak256 哈希的输出)将永远不会发生碰撞。
了解更多
如果你是 Solidity 的新手,请查看我们的免费初学者 Solidity 课程。
针对中高级开发者,请查看我们的专家级 Solidity 训练营。
最初发布于 2023 年 4 月 2 日