在 Solidity 中将 uint24 转换为 HEX 字符串

Convert uint24 to HEX string in Solidity

我正在尝试将一种 0x00ff08 的 uint24 值转换为人类可读的 string,在我将部署在 RSK 上的 Solidity 智能合约中具有相同的字符。在我关于 的问题中,有人建议我出于这些目的使用函数

function uint24tohexstr(uint24 i) public pure returns (string memory) {
        bytes memory o = new bytes(6);
        uint24 mask = 0x00000f;
        o[5] = bytes1(uint8tohexchar(uint8(i & mask)));
        i = i >> 4;
        o[4] = bytes1(uint8tohexchar(uint8(i & mask)));
        i = i >> 4;
        o[3] = bytes1(uint8tohexchar(uint8(i & mask)));
        i = i >> 4;
        o[2] = bytes1(uint8tohexchar(uint8(i & mask)));
        i = i >> 4;
        o[1] = bytes1(uint8tohexchar(uint8(i & mask)));
        i = i >> 4;
        o[0] = bytes1(uint8tohexchar(uint8(i & mask)));
        return string(o);
    }

我想在那个函数中使用一个循环并像这样重写它

function uint24ToHexStr(uint24 i) public pure returns (string memory) {
        bytes memory o = new bytes(6);
        uint24 mask = 0x00000f; // hex 15
        for(uint k = 5; k >= 0; k -= 1) {
          o[k] = bytes1(uint8ToHexCharCode(uint8(i & mask)));
          i >>= 4;
        }
        return string(o);
    }

但不幸的是,此函数会导致运行时错误,因为在最后一次迭代中,无符号整数 k 变为 -1。我首先想到的是将 k 增加 1,这样

        for(uint k = 6; k >= 1; k -= 1) {
          o[k - 1] = bytes1(uint8ToHexCharCode(uint8(i & mask)));
        }

谁能想出更优雅的方法来实现相同的结果?

这一行:

for(uint k = 5; k >= 0; k -= 1) {

如果 kuint 类型,k >= 0 什么时候会计算为 false? (提示:从不)

k 从类型 uint 更改为 int,问题就解决了。

    for(int k = 5; k >= 0; k -= 1) {
      o[k] = bytes1(uint8ToHexCharCode(uint8(i & mask)));
      i >>= 4;
    }

或者

    for(uint k = 0; k< 6; k += 1) {
      o[5-k] = bytes1(uint8ToHexCharCode(uint8(i & mask)));
      i >>= 4;
    }

我喜欢中的第二个选项;并想如果我们使用不同类型的循环控制结构会怎样。常规 while 循环会继承 for 循环所具有的相同“最终迭代 uint 下溢”问题。另一方面,切换到 do .. while 循环允许您将条件的评估从 迭代之前检查,转移到在 之后检查 迭代。这可以像这样应用于您的实现:

    function uint24ToHexStr(uint24 i) public pure returns (string memory) {
        bytes memory o = new bytes(6);
        uint24 mask = 0x00000f; // hex 15
        uint k = 6;
        do {
            k--;
            o[k] = bytes1(uint8ToHexCharCode(uint8(i & mask)));
            i >>= 4;
        } while (k > 0);
        return string(o);
    }

这既避免了 uint 下溢,也不需要 k - 1 用于循环内的数组索引。就 gas 成本而言,我会“猜测”它会接近上一个问题中相同功能的原始实现。 (但实际上都尝试并比较以确认)

替代答案,也从前向迭代中得到一些启发,但不是颠倒索引顺序, 通过按位与掩码 switching 获得目标半字节 到 5 个半字节(20 位)的位移。 像这样:

   function uint24ToHexStrAlt2(uint24 i) public pure returns (string memory) {
        bytes memory o = new bytes(6);
        uint k = 0;
        do {
            o[k] = bytes1(uint8ToHexCharCode(uint8(i >> 20))); // shift by 5 nibbles instead of mask
            i <<= 4;
            k +=1;
        } while (k < 6);
        return string(o);
    }