# 为什么bool比uint256消耗更多的gas **Published by:** [Canvie.crypto](https://paragraph.com/@canvie-crypto/) **Published on:** 2025-07-12 **URL:** https://paragraph.com/@canvie-crypto/bool-uint256-gas ## Content 之前遇到有朋友这么问:“为什么bool比uint256消耗更多的gas”。首先要说明的是这个说法是不准确的,并不是简单的bool和uint256这个类型差异造成的。我们在看OpenZeppelin的ReentrancyGuard.sol的源码时,会看到下面的写法,我们从底层机制上分析 // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. //..... uint256 private constant NOT_ENTERED = 1; uint256 private constant ENTERED = 2; 一. 首先,slot存储槽基本最小长度是256bit,EVM每次会按照整个slot进行读取,这个可以在instructions.go中找到“opSload”方法。 https://github.com/ethereum/go-ethereum/blob/master/core/vm/instructions.go val := interpreter.evm.StateDB.GetState(scope.Contract.Address(), hash) // 此处就是从slot中获取值,并不会判断变量的类型,直接返回整个32字节的内容 二. bool是1bit,如果是连续定义多个bool变量,编译器会把多个bool变量打包进同一个slot,用offset来定义每个变量的在slot中的位置。我们可以编译一段代码 contract Test { bool a; bool b; uint8 f; uint256 c; bool d; uint256 e; function getA() public view returns (bool){ return a; } function setA(bool _a) public { a = _a; } function getC() public view returns (uint256) { return c; } function setC(uint256 _c) public { c = _c; } function getD() public view returns (bool) { return d; } function setD(bool _d) public { d = _d; } } 在“Solidity Compile Details”中可以看到”STORAGELAYOUT” { "storage": [ { "astId": 3, "contract": "Test.sol:Test", "label": "a", "offset": 0, "slot": "0", "type": "t_bool" }, { "astId": 5, "contract": "Test.sol:Test", "label": "b", "offset": 1, "slot": "0", "type": "t_bool" }, { "astId": 7, "contract": "Test.sol:Test", "label": "f", "offset": 2, "slot": "0", "type": "t_uint8" }, { "astId": 9, "contract": "Test.sol:Test", "label": "c", "offset": 0, "slot": "1", "type": "t_uint256" }, { "astId": 11, "contract": "Test.sol:Test", "label": "d", "offset": 0, "slot": "2", "type": "t_bool" }, { "astId": 13, "contract": "Test.sol:Test", "label": "e", "offset": 0, "slot": "3", "type": "t_uint256" } ], "types": { "t_bool": { "encoding": "inplace", "label": "bool", "numberOfBytes": "1" }, "t_uint256": { "encoding": "inplace", "label": "uint256", "numberOfBytes": "32" }, "t_uint8": { "encoding": "inplace", "label": "uint8", "numberOfBytes": "1" } } } 我们可以看到a,b,f 所在slot的编号都是0,由此可以知道都被打包进了一个slot。但是d又是独占slot2。这里有个编译规则,如果是多个变量挤压在同一个slot中,则写的过程是SLOAD-SSTORE,如是变量独占一个slot,则写的过程就是SSTORE。前一个操作多了一个SLOAD,因此gas消费更多。 由此可以总结出 多个小变量打包进同一个 slot(如多个 bool、uint8、uint16),“单独写入”某个变量时,必须先 SLOAD slot(读出旧值)、在内存中修改对应 bit/byte、再 SSTORE(整体写回 slot)。 如果变量独占一个 slot(如 uint256、单独的 bool),写操作通常可以直接 SSTORE,不需要预读。 这个在初学的时候是非常容易混淆和不好理解的概念。 ## Publication Information - [Canvie.crypto](https://paragraph.com/@canvie-crypto/): Publication homepage - [All Posts](https://paragraph.com/@canvie-crypto/): More posts from this publication - [RSS Feed](https://api.paragraph.com/blogs/rss/@canvie-crypto): Subscribe to updates - [Twitter](https://twitter.com/huicanvie): Follow on Twitter