---
title: "Yulでパックされたストレージ変数を読み書きする方法"
description: "Yulでパックされたストレージ変数を読み書きする方法を理解する"
---

# Yulでパックされたストレージ変数を読み書きする方法

[Yul](http://www.alchemy.com/overviews/what-is-yul)は、[スマートコントラクト](https://www.alchemy.com/overviews/solidity-smart-contract)内でアセンブリ言語の一種を書くために使用できる中間プログラミング言語です。Yulの構文とストレージの仕組みについて学んだ後は、Yulでパックされたストレージ変数を読み書きする方法を理解することが重要です。

## **Yulでパックされたストレージ変数を読み書きする方法**

var5を4に変更したいとします。var5はslot 3にあることが分かっているので、次のようなコードを試すかもしれません。

getValInHex\(3\)を使うと、slot 3が次のように書き換えられていることが分かります。

`0x0000000000000000000000000000000000000000000000000000000000000004`

これは問題です。var4が0に書き換えられてしまっているからです。このセクションでは、パックされた変数の読み書き方法について説明しますが、その前にYulの構文についてもう少し学ぶ必要があります。

これらの演算に馴染みがなくても心配ありません。これから例を交えて説明していきます。

まずand\(\)から始めましょう。2つのbytes32を用意し、and\(\)演算子を試して、何が返されるか見てみます。

出力を見ると次のようになっています。

`0x0000000000000000000000009acc1d6aa9b846083e8a497a661853aae07f0f00`

これは、and\(\)が両方の入力の各ビットを見て、その値を比較するためです。

両方のビットが1である場合（バイナリで考えると、有効か無効か）、そのビットはそのまま保持されます。

それ以外の場合は0に設定されます。

次にor\(\)のコードを見てみましょう。

今回の出力は次の通りです。

`0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff`

これは、いずれかのビットが有効かどうかを見ているためです。

mask変数を次のように変更した場合を見てみましょう。

`0x00ffffffffffffffffffffff0000000000000000000000000000000000000000`

ご覧の通り、出力は次のように変わります。

`0x00ffffffffffffffffffffff9acc1d6aa9b846083e8a497a661853aae07f0f00`

最初のバイトが0x00になっている点に注目してください。どちらの入力も最初のバイトに有効なビットを持っていないためです。

xor\(\)は少し異なります。片方のビットが有効（1）で、もう片方のビットが無効（0）である必要があります。

**コードによるデモンストレーションは以下の通りです：**

出力は次の通りです。

`0xffffffffffffffffffffffff0000000000000000000000000000000000000000`

主な違いは、0x00と0xffが揃っている箇所でのみ出力に有効なビットが現れるという点に表れています。

shl\(\)とshr\(\)は互いに非常によく似た動作をします。どちらも入力値を、入力されたビット数だけシフトします。shl\(\)は左にシフトし、shr\(\)は右にシフトします。

コードを見てみましょう！

出力：

ans1: `0x0000ffff00000000000000000000000000000000000000000000000000000000`

ans2: `0x00000000000000000000000000000000000000000000000000000000ffff0000`

まずans1を見てみましょう。16ビット（2バイト）分shr\(\)を行っています。ご覧の通り、最後の2バイトが0xffffから0x0000に変わり、最初の2バイトが2バイト分右にシフトしています。これが分かれば、ans2は自明でしょう。起こっているのは、ビットが右ではなく左にシフトされるという違いだけです。

**var5に書き込む前に、まずvar4とvar5を読み取る関数を書いてみましょう。**

出力は期待通り1と2です。

var4を取得するには、値を次のように設定するマスクを使うだけです。

`0x0000000000000000000000000000000000000000000000000000000000000001`

そして、1に等しいuint128を返します。

var5を読み取る際は、var4を右にシフトすることで取り除く必要があります。

これにより、次のような値になり、これを返すことができます。

`0x0000000000000000000000000000000000000000000000000000000000000002`

複数の変数（2つ以上）が1つのストレージスロットにパックされている場合、値を読み取るためにシフトとマスクを同時に行う必要がある場合があることに注意してください。

**さて、いよいよvar5の値を4に変更する準備が整いました！**

最初のステップは、ストレージのslot 3をロードすることです。

次に、マスクを作成する必要があります。

var4を読み取ったときと同様に、値を次のように分離したいと思います。

`0x0000000000000000000000000000000000000000000000000000000000000001`

次のステップは、新しい値をvar5のスロット位置に合わせてフォーマットすることです。次のようになります。

`0x0000000000000000000000000000000400000000000000000000000000000000`

var5を読み取ったときとは異なり、今回は値を左にシフトします。

最後に、or\(\)を使って値を結合し、32バイトの16進数にして、その値をslot 3に格納します。

getValInHex\(3\)を呼び出すことで、作業内容を確認できます。

これにより、期待通り次の値が返されます。

`0x0000000000000000000000000000000400000000000000000000000000000001`

これで、パックされたストレージスロットの読み書き方法が分かりました！次は、Yulにおける[Memory](http://www.alchemy.com/overviews/yul-memory)、[Storage](http://www.alchemy.com/overviews/yul-storage)、[Smart Contract Calls](http://www.alchemy.com/overviews/yul-contract-calls)の仕組みについて学びましょう。
