【问题标题】:Convert uint24 to HEX string in Solidity在 Solidity 中将 uint24 转换为 HEX 字符串
【发布时间】:2021-09-25 18:02:46
【问题描述】:

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

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 加一,这样

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

谁能想到一种更优雅的方式来达到同样的效果?

【问题讨论】:

    标签: bit-manipulation solidity rsk


    【解决方案1】:

    这一行:

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

    如果kuint 类型,那么k >= 0 什么时候会评估为假? (提示:从不)

    kuint改成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;
        }
    

    【讨论】:

    • 对,永远不会计算为假,但在循环的最后一次迭代中,k 变为 -1,这对于 uint 是不可能的并导致错误!我正在使用 uints,因为在我看来,在辉煌的 Solidity 语言中,数组索引是 uints :) 但是你的第二个想法很好,谢谢!
    • 哦,我喜欢第二个选项!使用for 循环的巧妙方法,同时坚持使用uint 作为计数器变量!
    【解决方案2】:

    我喜欢@selbie's answer 中的第二个选项;并想如果我们使用不同类型的循环控制结构会怎样。常规的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 成本方面,我会“猜测”它会接近上一个问题中相同功能的原始实现。 (但实际上都尝试并比较确认)

    【讨论】:

      【解决方案3】:

      替代答案,也从前向迭代中获得了一些灵感from @selbie's answer,但不是颠倒索引顺序, 通过 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);
          }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-11-17
        • 2016-08-28
        • 2021-08-22
        • 1970-01-01
        • 2016-06-04
        • 2014-09-23
        • 2020-11-13
        • 2019-07-16
        相关资源
        最近更新 更多