highlight.js

星期五, 1月 26, 2018

ESP8266 Arduino Core 2.4.0 min() 與 max() 問題

ESP8266 Arduino Core 在更新到 2.4.0 時, 把原本是使用巨集定義的 min() 和 max() 改成使用 C++ 標準的 std::min() 和 std::max() 樣板 (template), 這使得許多使用到 min() 和 max() 的函式庫編譯錯誤, 這主要是因為原本巨集的版本大概如下 (以下均以 min() 為例, max() 的情況相同):
#define min(x, y) ((x) < (y) ? (x) : (y))
其中 x 與 y 可以是任意型別, 因此如果 x 是浮點數、y 是整數也可以成功編譯。可是改用了 std::min() 樣板, 它的原型如下 (事實上有多個版本, 但都有類似的問題):
template< class T > const T& min( const T& a, const T& b );
由於樣板中兩個比較的對象其資料型別都必須式樣板參數 T, 因此以下的程式編譯時就會有問題:
float val = 200;
void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
}

void loop() {
  // put your main code here, to run repeatedly:
  val = min(val, 210);
  Serial.print("min = ");
  Serial.println(val++);
  delay(200);
}
你會看到錯誤訊息為:
no matching function for call to 'min(float&, int)'
這是因為 val 是 float, 但是 210 是 int, 兩者型別不同, 所以無法用 std::min() 樣板建立對應呼叫的函式實體。要解決這個問題, 有兩種方法:一是在你的程式中自行定義巨集版本的 min(), 或者是在程式中強制轉型, 讓兩個比較的參數都是相同的型別, 例如:
 val = min((int)val, 210);就可以成功編譯, 也可以正確執行了。