6

I want to convert a bytes of length, say n, to a string in Solidity.

bytes memory ret = new bytes(3);
ret[0] = 0x41; // A
ret[1] = 0x42; // B
ret[2] = 0x43; // C
return string(ret); // results in ""

Doesn't work.

I get the empty string as result.

Any suggestions?

2
  • Try this ret[0]= byte(A); ret[1]= byte(B); ret[2]= byte(C); Commented Oct 26, 2017 at 12:04
  • Do you want to use char values for that? or can use just A, B, C? Commented Oct 26, 2017 at 14:10

2 Answers 2

2

This seems to be the go to code around here:

function bytes32ToString(bytes32 x) public 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);
}

I'm sure you can change out those 32's to get the length needed. But hope it helps!

3
  • What exactly does the function do?
    – Shuzheng
    Commented Oct 26, 2017 at 13:04
  • 1
    So as far as I understand, the EVM doesn't store strings, it stores things as bytes. So you can't store a string, you can just store bytes, which requires you to convert it if you want to do anything with it in Solidity. You've probably seen a lot of other posts to change string to bytes and that's in order to store the string in a way that you can call this function to get it back to a string.
    – thefett
    Commented Oct 26, 2017 at 15:18
  • Can I run this in Python? I don't know how to convert this into Python. Please help! Thanks
    – Russo
    Commented May 22, 2018 at 6:27
3

This function works correctly but will consume a lot of gas. You can use the fact that string and bytes are identical in terms of storage; it's only at the 'entry' and 'exit' points of the EVM that the values are treated differently.

You can use assembly to copy the data in 32 byte blocks like this:

function bytesToString(bytes memory byteCode) public pure returns(string memory stringData)
{
    uint256 blank = 0; //blank 32 byte value
    uint256 length = byteCode.length;

    uint cycles = byteCode.length / 0x20;
    uint requiredAlloc = length;

    if (length % 0x20 > 0) //optimise copying the final part of the bytes - to avoid looping with single byte writes
    {
        cycles++;
        requiredAlloc += 0x20; //expand memory to allow end blank, so we don't smack the next stack entry
    }

    stringData = new string(requiredAlloc);

    //copy data in 32 byte blocks
    assembly {
        let cycle := 0

        for
        {
            let mc := add(stringData, 0x20) //pointer into bytes we're writing to
            let cc := add(byteCode, 0x20)   //pointer to where we're reading from
        } lt(cycle, cycles) {
            mc := add(mc, 0x20)
            cc := add(cc, 0x20)
            cycle := add(cycle, 0x01)
        } {
            mstore(mc, mload(cc))
        }
    }

    //finally blank final bytes and shrink size (part of the optimisation to avoid looping adding blank bytes1)
    if (length % 0x20 > 0)
    {
        uint offsetStart = 0x20 + length;
        assembly
        {
            let mc := add(stringData, offsetStart)
            mstore(mc, mload(add(blank, 0x20)))
            //now shrink the memory back so the returned object is the correct size
            mstore(stringData, length)
        }
    }
}

If you specifically need bytes32ToString the code is even simpler; I can post it as a reply but it's probably not very useful. OP wanted bytes to string.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.