Bug
Solidity 的指數運算符中的意外隱式轉換
在調查 ERC20 中不正確的代幣獎勵錯誤時,發現關於指數運算符的鑄造存在明顯的不一致
a**b
。特別是,輸出轉換為 typeb
而不是 typea
。因此,當計算定義的小數位指數時
10**exp
,輸出被截斷為 8 位,給出的答案是而不是。exp``uint8 exp = 3``232``1000
如果基數被定義為
uint8
更長類型的指數,例如uint
,編譯器將拋出一個隱式轉換錯誤,表明輸出應該是基數類型而不是指數。這似乎不受非複合參數的影響,這些參數無論如何都轉換為 32 位插槽。
contract PowerOfTest { // Returns 232 uint8 public placesA = 3; uint public EXP_A = 10**placesA; // Returns 1000 uint public placesB = 3; uint public EXP_B = 10**placesB; // Returns 1000 uint8 public placesC = 3; uint public EXP_C = 10**uint(placesC); // Type uint256 is not implicity convertable to expected type uint 8 // uint public EXP_D = 3; // uint8 public placesD = 10**EXP_D; // Returns 1000 for `pow(10, 3)` function pow(uint base, uint8 exponent) returns(uint) { return base**exponent; } // Returns 232 for `pow(10, 3)` function pow2() returns(uint) { uint8 EXP_D = 3; return 10**EXP_D; } }
來自@chriseth 回應提出的 GH 問題…
Solidity 中任何二元運算符的結果類型(也承認 ** 作為非交換運算符應區別對待)是一種可以適合兩種參數類型的類型。表達式 a**b 的結果始終是 a 和 b 的“較大”類型。請注意,將表達式結果分配給的變數類型不會影響表達式本身的類型。
作為一種解決方案,我建議使用 uint(10)**placesA 並且只要 ** 運算符的基數是常量,編譯器就應該添加一個警告。
…常量一旦遇到非常數,就會假定它們適合的最小類型。
進一步閱讀文字的數學和類型轉換。