uint
Gibt es eine einfache Möglichkeit, a in Solidity umzuwandeln bytes
?
Es scheint jetzt so zu sein, seit der Solidity-Version 0.4.24 können Sie abi.encodePacked verwenden
Z.B:
uint i = 0;
i_bytes = abi.encodePacked(i);
Die Alternative zur Antwort von @eth ist die Verwendung von Assembly:
function toBytes(uint256 x) returns (bytes b) {
b = new bytes(32);
assembly { mstore(add(b, 32), x) }
}
Dies ist deutlich sparsamer, hängt jedoch vom internen Speicherlayout ab, das vom Solidity-Compiler verwendet wird. Theoretisch kann sich das in Zukunft ändern, aber in der Praxis sollte es ziemlich stabil sein.
Hier ist ein Vergleich des Gases, das in den drei Methoden von @NickJohnson, @Eth und @k26dr verwendet wird. Ich habe constant
den Funktionsmodifikatoren ein hinzugefügt, da diese Funktionen die Blockchain nicht verändern:
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];
}
}
}
Sie können die Gaskosten für die Ausführung dieser Funktionen in Remix (Solidity Browser) sehen:
Es gibt keine einfachen Möglichkeiten, etwas in bytes
. Hier ist eine Funktion:
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)))));
}
}
Basierend auf dem Chat von Solidity Gitter.
Wenn Sie sich übermäßig Sorgen um Benzin machen, können wir auch die Antwort von @NickJohnson verbessern.
function toBytes(uint _num) returns (bytes _ret) {
assembly {
_ret := mload(0x10)
mstore(_ret, 0x20)
mstore(add(_ret, 0x20), _num)
}
}
Dadurch werden die Benzinkosten um weitere 15 % gesenkt. Achten Sie jedoch darauf, dass Sie diesen Speicher nicht für etwas anderes verwenden, da 0x10 ein direkter Verweis auf den Speicher ist.
Wenn Sie ein 8-Bit-Int in Byte kopieren möchten, finden Sie hier eine Alternative, die nur die Hälfte der Gaskosten verbraucht:
function toByte(uint8 _num) returns (byte _ret) {
assembly {
mstore8(0x20, _num)
_ret := mload(0x20)
}
}
Denken Sie auch hier daran, dass 0x20 eine weitere direkte Speicherreferenz ist, und ehrlich gesagt würde ich bei dieser bleiben
function toByte(uint8 _num) returns (byte _ret) {
return byte(_num);
}
Der Gaspreis zwischen den beiden war fast identisch, aber das funktionierende ASM unterbot ihn um etwa 70 Wei
Bearbeiten: Wenn Sie Bedenken haben, den Speicher zu überschreiben, können Sie Folgendes verwenden:
let m_alloc := add(msize(),0x1)
Anstatt sich selbst auf die Erinnerung zu beziehen
Sie können in Bytes32 konvertieren und dann in Bytes konvertieren:
uint u = 200;
bytes32 b = bytes32(u);
bytes memory c = new bytes(32);
for (uint i=0; i < 32; i++) {
c[i] = b[i];
}
Sie können das Auffüllen des Bytes-Arrays mit Nullen bei den toBytes
Implementierungen vermeiden, indem Sie die scriptNumSize bestimmen
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)))));
}
}
Zum Beispiel würde uint 1563384765 0x5d2f5bbd zurückgeben, nicht 0x0000000000000000000000000000000000000000000000000000005d2f5bbd
Dies wurde speziell für Zeitstempel geschrieben. Wenn Sie größere Zahlen wünschen, können Sie weitere if-Fälle hinzufügen.
ppoliani
skgbanga
skgbanga
CJ42
bytes
Typ in Solidity wird im Speicher gespeichert als: 1) zuerst 32 Bytes = Länge desbytes
Werts, 2) dann derbytes
Wert selbst. Dermstore
Opcode speichert 32 Bytes, beginnend mit einem bestimmten Offset (in dem zu erfassenden Bytes-Wert) bis zu einer bestimmten Stelle im Speicher. Die Anweisungmstore(add(b, 32), x)
kann also in einfachen Worten übersetzt werden als "speichert 32 Bytes an Position x im Speicher, beginnend mit dem 32. Byte-Offset imb
" (um also die Länge zu überspringen und sich nurb
selbst zu speichern).