清理变量
最终,EVM中的所有数值都被存储在256位的字中。 因此,在某些情况下,当一个值的类型少于256比特时, 有必要清理剩余的比特位。 Solidity 编译器被设计为在任何可能受到剩余位中潜在垃圾的不利影响的操作之前执行这样的清理。 例如,在将一个值写入内存之前,剩余的位需要被清除, 因为内存的内容可以被用来计算哈希值或作为消息调用的数据发送。 同样地,在将一个值存储到存储器中之前,剩余的位需要被清理, 否则就会看到被混淆的数值。
注意,通过内联汇编的访问不被认为是这种操作。 如果您使用内联汇编来访问短于256位的Solidity变量,编译器不保证该值被正确清理。
此外,如果接下来的操作不受影响,我们就不清理这些位。
例如,由于任何非零值都被 JUMPI
指令认为是 true
,
所以在布尔值被用作 JUMPI
的条件之前,我们不对它们进行清理。
除了上面的设计原则外,Solidity编译器在输入数据被加载到堆栈时也会对其进行清理。
下表描述了适用于不同类型的清理规则,其中 高位
指的是在类型少于256位的情况下的剩余位。
类型 |
有效的值 |
清理无效值 |
---|---|---|
n 个成员的枚举 |
0,直到n - 1 |
抛出异常 |
布尔 |
0 或 1 |
结果为1 |
有符号整数 |
高位设置为符号位 |
目前默许符号化扩展到一个有效值 即所有高位被设置为符号位; 将来可能会抛出一个异常。 |
无符号整数 |
高位被清零 |
目前默许为有效值, 即所有高位被设置为零; 将来可能会抛出一个异常。 |
请注意,有效和无效的值取决于其类型大小。
假设类型为 uint8
,即无符号的8位类型,它有以下有效值:
0000...0000 0000 0000
0000...0000 0000 0001
0000...0000 0000 0010
....
0000...0000 1111 1111
任何无效的值都将把高位设置为零:
0101...1101 0010 1010 无效的值
0000...0000 0010 1010 清理过的值
对于 int8
,即有符号的8位类型,有效值是:
负数
1111...1111 1111 1111
1111...1111 1111 1110
....
1111...1111 1000 0000
正数
0000...0000 0000 0000
0000...0000 0000 0001
0000...0000 0000 0010
....
0000...0000 1111 1111
编译器将 符号化扩展(signextend)
符号位,即负值为1,正值为0,覆盖高位:
负数
0010...1010 1111 1111 无效的值
1111...1111 1111 1111 清理过的值
正数
1101...0101 0000 0100 无效的值
0000...0000 0000 0100 清理过的值