【无标题】solidity的内存分配(mload 0x40)

在某些情况下,我们希望在solidity中构造一个buffer,首先我们应该为这个buffer分配内存。在solidity中,只有bytes这样的结构给我们用,但是现在切片和替换对应位置的数据的操作在bytes上不容易实现。我们只好借助于assembly来完成,首先就是为buffer分配内存。
直接上代码:

struct buffer {
    bytes buf;
    uint capacity;
}

function init(buffer memory buf, uint capacity) internal pure returns(buffer memory) {
    if (capacity % 32 != 0) {
      capacity += 32 - (capacity % 32);
    }
    // Allocate space for the buffer data
    buf.capacity = capacity;
    assembly {
      let ptr := mload(0x40)
      mstore(buf, ptr)
      mstore(ptr, 0)
      mstore(0x40, add(32, add(ptr, capacity)))
    }
    return buf;
  }
我们先定义了一个结构体buffer,包含其内容buf和总容量capacity
再定义一个init方法(其实buffer是传入的,也可以用来resize).
以太坊在0x40地址保存了下一个可用的指针(free pointer)。

let ptr := mlod(0x40)

注意函数第一个参数buffer memory buf,有个memory关键字,说明buf也是在内存中的,buf是指针的别名,其值是buf对象存放的地址。

mstore(buf, ptr)

把可用的指针的地址替换了buf的地址

mstore(ptr ,0)

是把ptr地址的指向的数据变成0,也就是说把buf初始化成0,因为EVM不保证0x40地址中的指针指向的是全0数据

mstore(0x40, add(32, add(ptr, capacity)))

这行的作用是更新0x40的地址,指向下一个可用的指针。EVM不会处理0x40的更新,用户必须要自己处理。如何更新0x40的值呢?我们可以跳过刚刚开辟出来的buffer,把接下来的地址赋到0x40上。刚刚开辟的空间是capacity大小,再加上前32位(0x20)是数据的长度,所以0x40要在ptr的基础上偏移
capacity + 32

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 要截断 uint256 数组中的一部分值,你可以使用数组的 slice() 函数。 例如,假设你有一个名为 `myArray` 的 uint256 数组,你可以使用以下代码来截断数组的前 3 个元素: ``` myArray = myArray.slice(3); ``` 这样,`myArray` 将只包含原数组中索引 3 及以后的元素。 注意,这会在内存中重新创建一个新的数组,并将原数组中指定的元素复制到新数组中。如果你只是想修改数组的一部分并保留原数组,你可以使用数组的 `copy()` 函数来实现。 例如,假设你想将 `myArray` 的第 2 个元素替换为一个新值,你可以使用以下代码: ``` myArray.copy(myArray, 1, 2); ``` 这样,`myArray` 数组的第 2 个元素就会被替换为原数组的第 3 个元素的值,而原数组的其他元素都不会受到影响。 ### 回答2: 在Solidity中,可以使用缩影运算符`[]`来截断`uint256[]`类型的内存数组的一部分值。缩影运算符`[]`可以接受两个参数,即起始索引和结束索引。以下是一个示例代码: ```solidity function truncateArray(uint256[] memory arr, uint256 startIndex, uint256 endIndex) public pure returns (uint256[] memory) { require(endIndex >= startIndex, "Invalid index range"); require(endIndex < arr.length, "End index exceeds array length"); uint256[] memory truncatedArr = new uint256[](endIndex - startIndex + 1); for (uint256 i = startIndex; i <= endIndex; i++) { truncatedArr[i - startIndex] = arr[i]; } return truncatedArr; } ``` 在上述示例代码中,我们通过传入参数`arr`作为要截断的数组,`startIndex`作为截断的起始索引,`endIndex`作为截断的结束索引。 首先,我们校验输入参数的合法性,确保`endIndex`大于等于`startIndex`,并且`endIndex`不超过数组的长度。 接下来,我们根据截断部分的长度创建一个新的数组`truncatedArr`。 然后,使用`for`循环从`startIndex`到`endIndex`遍历原始数组,并将截断的值存储到`truncatedArr`中。 最后,返回截断后的新数组`truncatedArr`。 通过调用上述示例代码中的`truncateArray`函数,传入要截断的数组以及起始和结束索引,即可获得截断后的部分值的新数组。 ### 回答3: 在Solidity中,我们可以使用切片(slicing)来截断一个动态数组(array)或映射(mapping)。对于type memory uint256[]的动态数组,我们可以使用`Array.slice()`函数来截取所需的部分值。 示例如下: ```solidity pragma solidity ^0.8.0; contract SlicingExample { function sliceArray(uint256[] memory array, uint256 startPos, uint256 endPos) public pure returns (uint256[] memory) { uint256[] memory slicedArray = new uint256[](endPos - startPos); for (uint256 i = startPos; i < endPos; i++) { slicedArray[i - startPos] = array[i]; } return slicedArray; } } ``` 在上面的示例中,我们先声明了一个`sliceArray`函数,该函数接受一个动态数组`array`、截取的起始位置`startPos`和截取的结束位置`endPos`作为参数,并返回一个截取后的动态数组。 函数内部,我们先创建了一个新的动态数组`slicedArray`,其大小为`(endPos - startPos)`,即截取的长度。接着,我们使用循环遍历原始数组`array`的指定范围(从`startPos`到`endPos-1`),将每个元素逐一赋值给`slicedArray`。最后,我们返回截取后的`slicedArray`。 注意,在使用切片操作时,需要确保起始位置和结束位置在合理的范围内,避免越界访问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值