3

我正在学习 Solidity Assembly,但我对某些事情感到困惑。我正在查看这个名为 Seriality 的库。具体来说,这个函数:https ://github.com/pouladzade/Seriality/blob/master/src/TypesToBytes.sol#L21

function bytes32ToBytes(uint _offst, bytes32 _input, bytes memory _output) internal pure {
    assembly {
        mstore(add(_output, _offst), _input)
        mstore(add(add(_output, _offst),32), add(_input,32))
    }
}

该函数 bytes32ToBytes 采用 bytes32 变量并将其存储在动态大小的字节数组中,从传入的偏移量开始。

让我困惑的是它两次使用了 mstore 函数。但是 mstore 函数存储一个字,也就是 32 个字节,对吧?那么,既然输入是 32 字节,为什么它会被调用两次呢?不会两次调用它来存储 2 个字,即 64 字节吗?

谢谢!

4

2 回答 2

5

Solidity 数组的存储方式是将数组的大小写入第一个存储槽,然后将数据写入后续槽。

知道mstore有以下参数:mstore(START_LOCATION, ITEM_TO_STORE),第一条mstore语句写成如下:

mstore(add(_output, _offst), _input)

由于数组的第一个槽指向数组的大小,因此该语句设置_output. 您应该能够通过将其替换为mstore(add(_output, _offst), 32)(因为大小_input是静态的)来获得相同的结果。

第二个语句 ( mstore(add(add(_output, _offst),32), add(_input,32))) 是写入数据本身的语句。在这里,我们将两个指针的位置移动了 32 个字节(因为两个数组的前 32 个字节都指向大小)并将 的值存储_input到存储数据的位置_output

很可能,_output在调用此方法之前已经初始化(因此长度已经设置),因此通常是不必要的。但是,它不痛。请注意,做出此假设的类似实现如下所示:

function test() public pure returns (bytes) {
    bytes32 i = "some message";
    bytes memory o = new bytes(32); // Initializing this way sets the length to the location "o" points to. This replaces mstore(add(_output, _offst), _input).
    bytes32ToBytes(0, i, o);
    
    return o;
}

function bytes32ToBytes(uint _offst, bytes32 _input, bytes memory _output) internal pure {
    assembly {
        mstore(add(add(_output, _offst),32), add(_input,32))
    }
}
于 2018-07-03T16:44:10.950 回答
0

不确定该功能的意图bytes32ToBytes

如果是将 bytes32 转换为字节,我认为正确的实现应该是

pragma solidity ^0.7.0;

contract DecodeEncode {
    
    function test() public pure returns (bytes memory) {
        bytes32 i = "some message";
        bytes memory o = new bytes(32); // Initializing this way sets the length to the location "o" points to. This replaces mstore(add(_output, _offst), _input).
        bytes32ToBytes(0, i, o);
        
        return o;
    }

    function bytes32ToBytes(uint _offst, bytes32 _input, bytes memory _output) internal pure {
        assembly {
            mstore(add(_output, _offst), 32) //lineA
            mstore(add(add(_output, _offst), 32), _input) //lineB
        }
    }

}

lineA 将字节的长度设置为 32 字节
lineB 将字节的第一个槽的内容设置为_input

于 2021-08-26T10:40:33.560 回答