Is there an easy way to convert a uint to bytes in Solidity?
7 Answers
The alternative to @eth's answer is to use assembly:
function toBytes(uint256 x) returns (bytes b) {
b = new bytes(32);
assembly { mstore(add(b, 32), x) }
}
This is significantly more gas-efficient, but depends on the internal memory layout used by the Solidity compiler. In theory, this can change in future, but in practice it should be fairly stable.
- 8,144
- 1
- 28
- 35
It seems there now is, since solidity version 0.4.24 you can use abi.encodePacked
E.G:
uint i = 0;
i_bytes = abi.encodePacked(i);
- 396
- 2
- 4
Here's a comparison of the gas used in the three methods by @NickJohnson, @Eth and @k26dr. I've added a constant to the function modifiers as these functions do not alter the blockchain:
pragma solidity ^0.4.2;
contract Test {
function toBytesNickJohnson(uint256 x) constant returns (bytes b) {
b = new bytes(32);
assembly { mstore(add(b, 32), x) }
}
function toBytesEth(uint256 x) constant returns (bytes b) {
b = new bytes(32);
for (uint i = 0; i < 32; i++) {
b[i] = byte(uint8(x / (2**(8*(31 - i)))));
}
}
function toBytesNicolasMassart(uint256 x) constant returns (bytes c) {
bytes32 b = bytes32(x);
c = new bytes(32);
for (uint i=0; i < 32; i++) {
c[i] = b[i];
}
}
}
You can see the gas cost of running these functions in Remix (Solidity Browser):
- 670
- 1
- 5
- 14
- 40,274
- 14
- 123
- 193
There are no easy ways to convert anything to bytes. Here's a function:
function toBytes(uint256 x) returns (bytes b) {
b = new bytes(32);
for (uint i = 0; i < 32; i++) {
b[i] = byte(uint8(x / (2**(8*(31 - i)))));
}
}
Based on Solidity Gitter chat.
- 85,679
- 53
- 285
- 406
If you're overly concerned about gas we can improve on @NickJohnson answer too.
function toBytes(uint _num) returns (bytes _ret) {
assembly {
_ret := mload(0x10)
mstore(_ret, 0x20)
mstore(add(_ret, 0x20), _num)
}
}
This will shave approximately a further 15% off the gas cost, just be careful that you're not using that memory for something else as 0x10 is a direct reference to memory.
Also, if you want to copy an 8bit int to byte here's an alternative which only uses half the gas cost:
function toByte(uint8 _num) returns (byte _ret) {
assembly {
mstore8(0x20, _num)
_ret := mload(0x20)
}
}
Again, be mindful that 0x20 is another direct memory reference and in all honesty with this one I would stick with
function toByte(uint8 _num) returns (byte _ret) {
return byte(_num);
}
The gas price between the two was almost identical, but the functional ASM was undercutting it by about 70 wei
Edit: If you're concerned about overwriting memory you could use:
let m_alloc := add(msize(),0x1)
Instead of referencing memory yourself
- 514
- 4
- 7
-
I didn't know msize() can be used to increase the memory allocation by adding to it. The solidity assembly document (https://solidity.readthedocs.io/en/v0.4.24/assembly.html?highlight=calldatacopy) is very brief. Is there a better reference document out there? – Thomas Jul 20 '18 at 23:04
-
msize doesn't, it returns the highest point in memory and you simply state that you want to write to msize() plus 1. Here's another stack page where I explain it in more detail https://ethereum.stackexchange.com/questions/9537/how-to-return-dynamic-sized-arrays-original-address-on-the-memory-of-solidity – James Lockhart Jul 23 '18 at 16:20
You can convert to bytes32 then convert to bytes:
uint u = 200;
bytes32 b = bytes32(u);
bytes memory c = new bytes(32);
for (uint i=0; i < 32; i++) {
c[i] = b[i];
}
- 6,783
- 2
- 29
- 63
- 861
- 7
- 12
You can avoid padding the bytes array with 0's with the toBytes implementations by determining the scriptNumSize
function scriptNumSize(uint256 i) public view returns (uint256) {
if (i > 0x7fffffff) { return 5; }
else if (i > 0x7fffff ) { return 4; }
else if (i > 0x7fff ) { return 3; }
else if (i > 0x7f ) { return 2; }
else if (i > 0x00 ) { return 1; }
else { return 0; }
}
function toBytes(uint256 x) public view returns (bytes memory b) {
uint a = scriptNumSize(x);
b = new bytes(a);
for (uint i = 0; i < a; i++) {
b[i] = byte(uint8(x / (2**(8*(a - 1 - i)))));
}
}
For example uint 1563384765 would return 0x5d2f5bbd not 0x000000000000000000000000000000000000000000000000000000005d2f5bbd
This was written specifically for timestamps. If you want larger numbers you can add more if cases.
- 21
- 1

bytestype in Solidity is stored in memory as: 1) first 32 bytes = length of thebytesvalue, 2) then thebytesvalue itself. Themstoreopcode stores 32 bytes, starting from a certain offset (in the bytes value to grab) to a specified location in memory. So the instructionmstore(add(b, 32), x)can be translated in plain words as "stores 32 bytes at position x in memory, starting from the 32nd bytes offset in theb" (so to skip the length, and just storebitself). – CJ42 Dec 13 '21 at 00:01