2018-10-24 筆記
在Solidity - 引用類(lèi)型中提到订讼,當(dāng)沒(méi)有給局部變量的uint[] storage p
賦值的時(shí)候,p
會(huì)默認(rèn)指向storage
的第一個(gè)slot
华坦。
首先昆咽,slot
的英文翻譯是指容器的插槽躬厌、投幣口,暫時(shí)先不解釋這個(gè)東西狠裹。先看看storage
虽界,官方對(duì)storage
的解釋是
Every account has a persistent key-value store mapping 256-bit words to 256-bit words called storage.
中文意思是,storage
是一個(gè)持久化的存儲(chǔ)區(qū)涛菠,它將32字節(jié)的鍵映射到32字節(jié)的鍵莉御。
簡(jiǎn)單理解就是,storage
是一個(gè)超大的數(shù)組俗冻,數(shù)組可以看成儲(chǔ)物柜礁叔,slot
就是一個(gè)個(gè)的小柜子。
其中每一個(gè)slot
的大小是32
字節(jié)迄薄,slot0
的地址(即storage
的起始地址)是0x00
琅关。Solidity對(duì)聲明時(shí)候沒(méi)有進(jìn)行初始化的變量,都默認(rèn)值為0讥蔽。因此p
作為一個(gè)指針涣易,其中指針的值就是內(nèi)存的地址(這點(diǎn)與C語(yǔ)言指針一樣),因此它會(huì)指向slot0
冶伞。至于為什么a
的值變了新症,當(dāng)然就是因?yàn)?code>a存儲(chǔ)在了slot0
。
下面整理一下storage
內(nèi)存布局的幾條規(guī)則:
- 變量位置按照聲明的順序响禽,從
slot0
開(kāi)始排序徒爹。因此a
存儲(chǔ)在了slot0
。 - 變量占用的內(nèi)存大小與他定義的類(lèi)型一致芋类,也就是
uint256
占用32
個(gè)字節(jié)瀑焦,uint8
占用1
個(gè)字節(jié)。 - 如果一個(gè)變量不能完全存在一個(gè)
slot
中梗肝,那么他就從下一個(gè)slot
開(kāi)始存儲(chǔ)榛瓮。
uint8 a; //存儲(chǔ)在slot0
uint256 b; //因?yàn)閟lot0剩余的空間不夠存下一個(gè)uint256,則從slot1開(kāi)始存儲(chǔ)巫击,另外uint 相當(dāng)于 uint256
-
structs
和arrays
總是在一個(gè)新的slot
中開(kāi)始存儲(chǔ)禀晓,并且占用整個(gè)slot
精续,但每一個(gè)元素是緊緊相挨的。
pragma solidity ^0.4.0;
contract hello {
struct items {
uint8 a;
uint8 b;
}
items[3] public items_arr;
}
items_arr
數(shù)組有三個(gè)元素粹懒,他們的內(nèi)存占用情況是重付,首先struct items
的內(nèi)存占用是2字節(jié),然后按照一個(gè)struct
占用一個(gè)slot
的話凫乖,那么items_arr
占用了3*32
的字節(jié)确垫,其中很多都浪費(fèi)了。(這個(gè)其實(shí)我自己也不太肯定帽芽,因?yàn)槭褂肦emix調(diào)試的時(shí)候删掀,看不到storage
內(nèi)存詳情,也許要通過(guò)指令集來(lái)判斷导街,這里暫時(shí)存疑披泪,以后驗(yàn)證再補(bǔ)充。XXX)
Arrays的存儲(chǔ)方式
arrays
有兩種類(lèi)型搬瑰,靜態(tài)長(zhǎng)度uint[3]
與動(dòng)態(tài)長(zhǎng)度uint[]
款票。靜態(tài)長(zhǎng)度的話,在編譯的時(shí)候泽论,就可以確定他的內(nèi)存占用大小艾少,因此可以提前分配。但是動(dòng)態(tài)長(zhǎng)度的array
翼悴,他的元素大小是不確定的姆钉,因此需要使用別的方式來(lái)存儲(chǔ)動(dòng)態(tài)長(zhǎng)度的數(shù)組。舉個(gè)例子:
pragma solidity ^0.4.0;
contract hello {
uint a;
uint[] public b;
uint c;
uint[3] d;
}
其中a
的位置是slot0
抄瓦,那么b
的位置是slot1
潮瓶,c
的位置是slot2
,d
的位置是slot3
-slot5
钙姊√焊ǎ可以看到動(dòng)長(zhǎng)數(shù)組只占用了一個(gè)slot
,然后這個(gè)位置用來(lái)存放動(dòng)長(zhǎng)數(shù)組的長(zhǎng)度煞额,即b.lenght
的值思恐。動(dòng)態(tài)數(shù)組的元素存儲(chǔ)在其他的位置,這個(gè)位置根據(jù)keccak256()
方法計(jì)算出來(lái)膊毁,比如b[1]
的位置就是keccak256(1 . p)
胀莹。其中p
是b
所在slot1
的起始地址0x32
(因?yàn)橐粋€(gè)slot
占32
個(gè)字節(jié)),另外.
代表的是連接符婚温。
Mappings的存儲(chǔ)方式
Mappings
也會(huì)占用一個(gè)slot
描焰,但是這個(gè)slot
是空的,不記錄東西,用來(lái)做為尋找元素的基址荆秦,尋址方式則跟Arrays
的一樣篱竭。