閱讀500 返回首頁    go 技術社區[雲棲]


『0015』 - Solidity Types - 動態字節數組(Dynamically-sized byte array)、固定大小字節數組(Fixed-size byte arrays)、string之間的轉換關係

孔壹學院:國內區塊鏈職業教育領先品牌

作者:黎躍春,區塊鏈、高可用架構工程師
微信:liyc1215 QQ群:348924182 博客:https://liyuechun.org

固定大小字節數組(Fixed-size byte arrays)之間的轉換

固定大小字節我們可以通過bytes0 ~ bytes32來進行聲明,固定大小字節數組的長度不可變,內容不可修改。接下來我們通過下麵的代碼看看固定大小字節之間的轉換關係。

pragma solidity ^0.4.4;

contract C {


   bytes9 name9 = 0x6c697975656368756e;


   function bytes9ToBytes1() constant returns (bytes1) {

       return bytes1(name9);
   }

   function bytes9ToBytes2() constant returns (bytes2) {

       return bytes2(name9);
   }

   function bytes9ToBytes32() constant returns (bytes32) {

       return bytes32(name9);
   }

}

固定大小字節之間的轉換

結論:bytes9bytes1或者bytes2時,會進行低位截斷,0x6c697975656368756e轉換為bytes1,結果為0x6c,轉換為bytes2時結果為0x6c69。當0x6c697975656368756e轉換為bytes32時會進行低位補齊,結果為0x6c697975656368756e0000000000000000000000000000000000000000000000

固定大小字節數組(Fixed-size byte arrays)轉動態大小字節數組(Dynamically-sized byte array)

pragma solidity ^0.4.4;

contract C {


   bytes9 name9 = 0x6c697975656368756e;

   function fixedSizeByteArraysToDynamicallySizedByteArray() constant returns (bytes) {

       return bytes(name9);
   }

}

對於剛接觸的童鞋,很多人都會用上麵的方法進行轉換,以為理所當然,殊不知編譯運行時,代碼報錯,原因如下:

固定大小字節數組轉動態大小字節數組

備注:簡言之,固定大小字節數組動態大小字節數組之間不能簡單直接轉換。

下麵是固定大小字節數組轉動態大小字節數組正確的姿勢。

pragma solidity ^0.4.4;

contract C {

   bytes9 name9 = 0x6c697975656368756e;

   function fixedSizeByteArraysToDynamicallySizedByteArray() constant returns (bytes) {

       bytes memory names = new bytes(name9.length);

       for(uint i = 0; i < name9.length; i++) {

           names[i] = name9[i];
       }

       return names;
   }

}

在上麵的代碼中,我們根據固定字節大小數組的長度來創建一個memory類型的動態類型的字節數組,然後通過一個for循環將固定大小字節數組中的字節按照索引賦給動態大小字節數組即可。

固定大小字節數組(Fixed-size byte arrays)不能直接轉換為string

pragma solidity ^0.4.4;

contract C {

    bytes9 names = 0x6c697975656368756e;

    function namesToString() constant returns (string) {

        return string(names);
    }

}

定大小字節數組(Fixed-size byte arrays)不能直接轉換為string

動態大小字節數組(Dynamically-sized byte array)轉string

重要:因為string是特殊的動態字節數組,所以string隻能和動態大小字節數組(Dynamically-sized byte array)之間進行轉換,不能和固定大小字節數組進行轉行。

  • 如果是現成的動態大小字節數組(Dynamically-sized byte array),如下:
pragma solidity ^0.4.4;

contract C {

    bytes names = new bytes(2);

    function C() {

        names[0] = 0x6c;
        names[1] = 0x69;
    }


    function namesToString() constant returns (string) {

        return string(names);
    }

}

如果是現成的動態大小字節數組(Dynamically-sized byte array)

  • 如果是固定大小字節數組轉string,那麼就需要先將字節數組轉動態字節數組,再轉字符串
pragma solidity ^0.4.4;

contract C {

   function byte32ToString(bytes32 b) constant returns (string) {

       bytes memory names = new bytes(b.length);

       for(uint i = 0; i < b.length; i++) {

           names[i] = b[i];
       }

       return string(names);
   }

}

如果是固定大小字節數組轉string,那麼就需要先將字節數組轉動態字節數組,再轉字符串
可以通過0x6c697975656368756e作為參數進行測試,右邊的返回結果**看似**為liyuechun,它的實際內容為liyuechun\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000,所以在實際的操作中,我們應該將後麵的一些列\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000去掉。

  • 正確的固定大小字節數組轉string的代碼
pragma solidity ^0.4.4;

contract C {

    function bytes32ToString(bytes32 x) constant returns (string) {
        bytes memory bytesString = new bytes(32);
        uint charCount = 0;
        for (uint j = 0; j < 32; j++) {
            byte char = byte(bytes32(uint(x) * 2 ** (8 * j)));
            if (char != 0) {
                bytesString[charCount] = char;
                charCount++;
            }
        }
        bytes memory bytesStringTrimmed = new bytes(charCount);
        for (j = 0; j < charCount; j++) {
            bytesStringTrimmed[j] = bytesString[j];
        }
        return string(bytesStringTrimmed);
    }

    function bytes32ArrayToString(bytes32[] data) constant returns (string) {
        bytes memory bytesString = new bytes(data.length * 32);
        uint urlLength;
        for (uint i = 0; i< data.length; i++) {
            for (uint j = 0; j < 32; j++) {
                byte char = byte(bytes32(uint(data[i]) * 2 ** (8 * j)));
                if (char != 0) {
                    bytesString[urlLength] = char;
                    urlLength += 1;
                }
            }
        }
        bytes memory bytesStringTrimmed = new bytes(urlLength);
        for (i = 0; i < urlLength; i++) {
            bytesStringTrimmed[i] = bytesString[i];
        }
        return string(bytesStringTrimmed);
    }    
}

byte char = byte(bytes32(uint(x) * 2 ** (8 * j)))在上麵的代碼中,估計大家最難看懂的就是這一句代碼,我們通過下麵的案例給大家解析:

pragma solidity ^0.4.4;

contract C {

    // 0x6c

    function uintValue() constant returns (uint) {

        return uint(0x6c);
    }

    function bytes32To0x6c() constant returns (bytes32) {

        return bytes32(0x6c);
    }

    function bytes32To0x6cLeft00() constant returns (bytes32) {

        return bytes32(uint(0x6c) * 2 ** (8 * 0));
    }

    function bytes32To0x6cLeft01() constant returns (bytes32) {

        return bytes32(uint(0x6c) * 2 ** (8 * 1));
    }

    function bytes32To0x6cLeft31() constant returns (bytes32) {

        return bytes32(uint(0x6c) * 2 ** (8 * 31));
    }
}

  • bytes32(uint(0x6c) * 2 ** (8 * 31));左移31位
  • bytes32(uint(0x6c) * 2 ** (8 * 1)); 左移1位

通過byte(bytes32(uint(x) * 2 ** (8 * j)))獲取到的始終是第0個字節。

總結

string本身是一個特殊的動態字節數組,所以它隻能和bytes之間進行轉換,不能和固定大小字節數組進行直接轉換,如果是固定字節大小數組,需要將其轉換為動態字節大小數組才能進行轉換。

技術交流

  • 區塊鏈技術交流QQ群:348924182

  • 「區塊鏈部落」官方公眾號

最後更新:2017-10-27 22:04:46

  上一篇:go  詳解Docker 最低特權編排原則,安全與效率並行!(一)
  下一篇:go  『0014』 - Solidity Types - 動態大小字節數組(Dynamically-sized byte array)