当把多个参数打包成struct,传递给函数的就只有一个引用(栈上的一个指针),而不是多个独立的值。如果struct在memory中:函数接收到的是一个memory指针(通常占用一个栈槽)。如果struct在calldata中:函数接收到的是一个calldata偏移量
当把多个参数打包成 struct,传递给函数的就只有一个引用(栈上的一个指针),而不是多个独立的值。
struct 在 memory 中:函数接收到的是一个 memory 指针(通常占用一个栈槽)。struct 在 calldata 中:函数接收到的是一个 calldata 偏移量(同样一个栈槽)。struct 在 storage 中:传递的是 storage 引用(一个栈槽)。函数内部访问字段时,通过指针 + 偏移量读取,这比逐个读取栈变量更紧凑、操作码更少。尤其是结合 calldata,完全避免了 ABI 解码的开销,因为你可以直接从 calldata 里按需 load,编译器不会生成一长串解码逻辑。
struct Order {
address user;
uint128 amount;
uint64 deadline;
bool active;
}
function process(Order calldata order) external pure returns (uint256) {
// 只有 1 个 calldata 引用传进来,无繁重解码
return _internalProcess(order);
}
function _internalProcess(Order calldata order) internal pure returns (uint256) {
if (order.active && order.deadline > uint64(block.timestamp)) {
return uint256(uint160(order.user)) + order.amount;
}
return 0;
}
Gas 变化:
process 入口的 ABI 解码几乎为空:它只从 calldata 读取一个偏移量,赋给 order 指针。原本 4 个参数需要的 4 次 CALLDATALOAD + 可能的 AND 掩码操作全部取消。_internalProcess 只接收一个指针,栈操作从 4 个值缩减为 1 个,字节码体积明显缩小。CALLDATALOAD 按偏移读取,按需加载,不需要的字段甚至完全不读取。实测中,这种优化能节省 数百到数千 gas,字段越多越明显。
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!
作者暂未设置收款二维码