Struct
解除安裝。使用結構 - 載入字節
我正在嘗試從程序集中的結構中載入各種字節。我在這裡找到了 uint的一個很好的解釋。雖然這適用於 uint 和整個記憶體插槽,但我無法弄清楚如何從結構中獲取 bytes1 或 bytes12 變數。
contract Storage { mapping(uint256 => turmite) public turmites; struct turmite { bytes1 state; bytes12 baserule; } bytes1 state = hex"02"; constructor(){ turmites[1] = turmite( state, 0xff0801ff0201ff0000000001 ); } function retrieve(uint id) public{ turmite storage data = turmites[id]; bytes12 b; bytes1 a; bytes32 completeslot; assembly { let w := sload(data.slot) completeslot := w a := and(w, 0xff) } } }
字節和字元串左對齊,而數字(即uintX)右對齊。
- 字節32(字節1(0xFF))-> 0xFF0…00
- uint256(uint8(0xFF)) -> 0x00…0FF
導致這種行為:
function test() public view returns (bytes1) { uint256 value = 0xFF00000000000000000000000000000000000000000000000000000000000000; bytes1 rvalue; assembly { rvalue := value } return rvalue; // 0xFF }
SLOAD 返回一個 uint256,當嘗試將此值放入 bytes1 時,您實際上得到的是 uint 的第 32 個字節(在整個答案中,字節 32 位於最左側,字節 0 位於最右側),而不是第一個。使用 bytes12,您將獲得 32 到 20 的範圍,而不是 12 到 0 的範圍。
這正是發生的情況:
// clears bytes 32 to 1 and puts byte 32 into a // because a is byte1 : left aligned a := and(w, 0xff)
您可以直接在 int 上工作,並且只能在返回裝配塊之前進行轉換,如下所示:
function retrieve(uint id) public view returns (bytes1, bytes12) { turmite storage data = turmites[id]; uint96 b; uint8 a; assembly { let w := sload(data.slot) a := w b := shr(8, w) } return (bytes1(a), bytes12(b)); }
或者堅持使用 bytesX 並將您的值向左移動,因為這是它們將被拾取的地方:
function retrieve(uint id) public view returns (bytes1, bytes12) { turmite storage data = turmites[id]; bytes12 b; bytes1 a; assembly { let w := sload(data.slot) // Shift 152 bits (19 bytes) left to bring data.baserule at byte 32 b := shl(152, w) // shift 248 bits (31 bytes) left to bring data.state at byte 32 a := shl(248, w) } return (a, b); }