如何在 C++ 宏中格式化 "if" 语句(以及如何使用 Arduino 的新 EEPROM 库获取和放置函数)

How to format "if" statement in C++ macro (& how to use Arduino's new EEPROM library get & put functions)

2016 年 1 月 3 日更新:我现在也回答了我自己的问题。

我需要一些帮助来格式化此 C++ 宏中的 "if" 语句:

#define updateEEPROMVal(address,val)  if (EEPROM.get(address)!=val) \
                                        EEPROM.put(address,val)

我收到了多页错误,所以我假设这是一个简单的格式问题。

2020 年 4 月更新: 直接跳转到 。我的宏很好(用 do {} while (false) 包围它当然会更好,但它原样很好)。我只是忘记了 EEPROM.get() 中的第二个参数。第二个参数由 NON-const C++ 引用传递,当时我并不知道什么是引用或它是如何工作的,所以我没有正确使用 .get() 方法。就是这样!

回到我 2016 年的原始问题:

完整上下文如下:

//----------------------------------------------------------------------------------------------------------------------------------
//storeXYValsIntoEEPROM
//-store the current global variable x and y low, center, and high values into EEPROM
//----------------------------------------------------------------------------------------------------------------------------------
#define updateEEPROMVal(address,val)  if (EEPROM.get(address)!=val) \
                                        EEPROM.put(address,val)
void storeXYValsIntoEEPROM()
{
  //update EEPROM values *only* if necessary, this way you minimize writes (and wear-and-tear) on the EEPROM, since it is limited to
  //100k writes per cell I believe (see datasheet)
  updateEEPROMVal(0,x_low);
  updateEEPROMVal(2,x_ctr);
  updateEEPROMVal(4,x_high);
  updateEEPROMVal(6,y_low);
  updateEEPROMVal(8,y_ctr);
  updateEEPROMVal(10,y_high);
}

更新:这是我的错误输出:

Arduino: 1.6.5 (Windows 8.1), Board: "Arduino Uno"  

Using library IRremote in folder: C:\Gabe\Gabe - RC-extra\Arduino\Sketches\libraries\IRremote (legacy)  

Using library eRCaGuy_ButtonReader in folder: C:\Gabe\Gabe - RC-extra\Arduino\Sketches\libraries\eRCaGuy_ButtonReader (legacy)  

Using library EEPROM in folder: C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\EEPROM   



C:\Program Files (x86)\Arduino\hardware\tools\avr/bin/avr-g++ -c -g -Os -Wall -Wextra -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -MMD -mmcu=atmega328p -DF_CPU=16000000L -DARDUINO=10605 -DARDUINO_AVR_UNO -DARDUINO_ARCH_AVR -IC:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino -IC:\Program Files (x86)\Arduino\hardware\arduino\avr\variants\standard -IC:\Gabe\Gabe - RC-extra\Arduino\Sketches\libraries\IRremote -IC:\Gabe\Gabe - RC-extra\Arduino\Sketches\libraries\eRCaGuy_ButtonReader -IC:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\EEPROM C:\Users\Gabriel\AppData\Local\Temp\build6111239347405487460.tmp\IR_Tx_code5_w_calibration_mode.cpp -o   C:\Users\Gabriel\AppData\Local\Temp\build6111239347405487460.tmp\IR_Tx_code5_w_calibration_mode.cpp.o   

In file included from IR_Tx_code5_w_calibration_mode.ino:27:0:
C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\EEPROM/EEPROM.h:43:30: warning: type qualifiers ignored on function return type [-Wignored-qualifiers]
     operator const uint8_t() const       { return **this; }  
                              ^
C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\EEPROM/EEPROM.h:92:26: warning: type qualifiers ignored on function return type [-Wignored-qualifiers]
     operator const int() const          { return index; }  
                          ^
IR_Tx_code5_w_calibration_mode.ino: In function 'void storeXYValsIntoEEPROM()':
IR_Tx_code5_w_calibration_mode.ino:430:61: error: no matching function for call to 'EEPROMClass::get(int)'
IR_Tx_code5_w_calibration_mode.ino:436:3: note: in expansion of macro 'updateEEPROMVal'
IR_Tx_code5_w_calibration_mode.ino:430:61: note: candidate is:
IR_Tx_code5_w_calibration_mode.ino:436:3: note: in expansion of macro 'updateEEPROMVal'
In file included from IR_Tx_code5_w_calibration_mode.ino:27:0:
C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\EEPROM/EEPROM.h:130:31: note: template<class T> T& EEPROMClass::get(int, T&)
     template< typename T > T &get( int idx, T &t ){  
                               ^
C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\EEPROM/EEPROM.h:130:31: note:   template argument deduction/substitution failed:
IR_Tx_code5_w_calibration_mode.ino:430:61: note:   candidate expects 2 arguments, 1 provided
IR_Tx_code5_w_calibration_mode.ino:436:3: note: in expansion of macro 'updateEEPROMVal'
IR_Tx_code5_w_calibration_mode.ino:430:61: error: no matching function for call to 'EEPROMClass::get(int)'
IR_Tx_code5_w_calibration_mode.ino:437:3: note: in expansion of macro 'updateEEPROMVal'
IR_Tx_code5_w_calibration_mode.ino:430:61: note: candidate is:
IR_Tx_code5_w_calibration_mode.ino:437:3: note: in expansion of macro 'updateEEPROMVal'
In file included from IR_Tx_code5_w_calibration_mode.ino:27:0:
C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\EEPROM/EEPROM.h:130:31: note: template<class T> T& EEPROMClass::get(int, T&)
     template< typename T > T &get( int idx, T &t ){  
                               ^
C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\EEPROM/EEPROM.h:130:31: note:   template argument deduction/substitution failed:
IR_Tx_code5_w_calibration_mode.ino:430:61: note:   candidate expects 2 arguments, 1 provided
IR_Tx_code5_w_calibration_mode.ino:437:3: note: in expansion of macro 'updateEEPROMVal'
IR_Tx_code5_w_calibration_mode.ino:430:61: error: no matching function for call to 'EEPROMClass::get(int)'
IR_Tx_code5_w_calibration_mode.ino:438:3: note: in expansion of macro 'updateEEPROMVal'
IR_Tx_code5_w_calibration_mode.ino:430:61: note: candidate is:
IR_Tx_code5_w_calibration_mode.ino:438:3: note: in expansion of macro 'updateEEPROMVal'
In file included from IR_Tx_code5_w_calibration_mode.ino:27:0:
C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\EEPROM/EEPROM.h:130:31: note: template<class T> T& EEPROMClass::get(int, T&)
     template< typename T > T &get( int idx, T &t ){  
                               ^
C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\EEPROM/EEPROM.h:130:31: note:   template argument deduction/substitution failed:
IR_Tx_code5_w_calibration_mode.ino:430:61: note:   candidate expects 2 arguments, 1 provided
IR_Tx_code5_w_calibration_mode.ino:438:3: note: in expansion of macro 'updateEEPROMVal'
IR_Tx_code5_w_calibration_mode.ino:430:61: error: no matching function for call to 'EEPROMClass::get(int)'
IR_Tx_code5_w_calibration_mode.ino:439:3: note: in expansion of macro 'updateEEPROMVal'
IR_Tx_code5_w_calibration_mode.ino:430:61: note: candidate is:
IR_Tx_code5_w_calibration_mode.ino:439:3: note: in expansion of macro 'updateEEPROMVal'
In file included from IR_Tx_code5_w_calibration_mode.ino:27:0:
C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\EEPROM/EEPROM.h:130:31: note: template<class T> T& EEPROMClass::get(int, T&)
     template< typename T > T &get( int idx, T &t ){  
                               ^
C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\EEPROM/EEPROM.h:130:31: note:   template argument deduction/substitution failed:
IR_Tx_code5_w_calibration_mode.ino:430:61: note:   candidate expects 2 arguments, 1 provided
IR_Tx_code5_w_calibration_mode.ino:439:3: note: in expansion of macro 'updateEEPROMVal'
IR_Tx_code5_w_calibration_mode.ino:430:61: error: no matching function for call to 'EEPROMClass::get(int)'
IR_Tx_code5_w_calibration_mode.ino:440:3: note: in expansion of macro 'updateEEPROMVal'
IR_Tx_code5_w_calibration_mode.ino:430:61: note: candidate is:
IR_Tx_code5_w_calibration_mode.ino:440:3: note: in expansion of macro 'updateEEPROMVal'
In file included from IR_Tx_code5_w_calibration_mode.ino:27:0:
C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\EEPROM/EEPROM.h:130:31: note: template<class T> T& EEPROMClass::get(int, T&)
     template< typename T > T &get( int idx, T &t ){  
                               ^
C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\EEPROM/EEPROM.h:130:31: note:   template argument deduction/substitution failed:
IR_Tx_code5_w_calibration_mode.ino:430:61: note:   candidate expects 2 arguments, 1 provided
IR_Tx_code5_w_calibration_mode.ino:440:3: note: in expansion of macro 'updateEEPROMVal'
IR_Tx_code5_w_calibration_mode.ino:430:61: error: no matching function for call to 'EEPROMClass::get(int)'
IR_Tx_code5_w_calibration_mode.ino:441:3: note: in expansion of macro 'updateEEPROMVal'
IR_Tx_code5_w_calibration_mode.ino:430:61: note: candidate is:
IR_Tx_code5_w_calibration_mode.ino:441:3: note: in expansion of macro 'updateEEPROMVal'
In file included from IR_Tx_code5_w_calibration_mode.ino:27:0:
C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\EEPROM/EEPROM.h:130:31: note: template<class T> T& EEPROMClass::get(int, T&)
     template< typename T > T &get( int idx, T &t ){  
                               ^
C:\Program Files (x86)\Arduino\hardware\arduino\avr\libraries\EEPROM/EEPROM.h:130:31: note:   template argument deduction/substitution failed:
IR_Tx_code5_w_calibration_mode.ino:430:61: note:   candidate expects 2 arguments, 1 provided
IR_Tx_code5_w_calibration_mode.ino:441:3: note: in expansion of macro 'updateEEPROMVal'  
Multiple libraries were found for "IRremote.h"  

 Used: C:\Gabe\Gabe - RC-extra\Arduino\Sketches\libraries\IRremote  

 Not used: C:\Program Files (x86)\Arduino\libraries\RobotIRremote  

no matching function for call to 'EEPROMClass::get(int)'  

使用 do{...}while(0) 宏编码(不要忘记分号):

 #define updateEEPROMVal(address,val)  do{if (EEPROM.get(address)!=val) \
                                    EEPROM.put(address,val);}while(0)

另见 this

更好的是,将其设为 static inline 函数(放入某个头文件中)。

还有,用g++ -C -E source.cc > source.ii得到预处理后的表格,可以往里看

不需要这个。当我编写库时,我确保它最大限度地减少了磨损。

EEPROM函数put()使用字节级别的更新方式。 您只是在复制功能。

如果您对 EEPROM 库有更多疑问,请在论坛上提问。

我专门为我的图书馆创建了一个主题:https://forum.arduino.cc/index.php?topic=312645

我的答案:

很抱歉给您带来麻烦,原来我误用了 EEPROM.get 函数,问题根本不是我的宏。 EEPROM 库 get() 方法定义:https://github.com/arduino/ArduinoCore-avr/blob/master/libraries/EEPROM/src/EEPROM.h#L130, and the documentation here: https://www.arduino.cc/en/Reference/EEPROMGet

我只是错过了第二个参数,不小心使用了这个:

EEPROM.get(address);

...而不是这个:

any_type val_in_EEPROM;
EEPROM.get(address, val_in_EEPROM);

这是我在这项工作中提出的 2 个解决方案。

1) 使用单独的函数:

-我更喜欢这种方法。原来 "inline" 在这种情况下是可选的,没有区别。
- 这种方法使我的程序有 7610 字节,其中 472 字节用于全局变量。它比下面的选项 2 少占用 162 字节的内存。

inline void updateEEPROMVal(uint16_t address, uint16_t val)
{
  uint16_t val_in_EEPROM;
  EEPROM.get(address,val_in_EEPROM);
  if (val_in_EEPROM!=val)
    EEPROM.put(address,val);
}

void storeGlobalXYValsIntoEEPROM()
{
  updateEEPROMVal(0,x_low);
  updateEEPROMVal(2,x_ctr);
  updateEEPROMVal(4,x_high);
  updateEEPROMVal(6,y_low);
  updateEEPROMVal(8,y_ctr);
  updateEEPROMVal(10,y_high);
}

2)使用宏,如下:

-我更喜欢上面的方法
- 该方法对程序 space 占用 7772 字节,对全局变量占用 472 字节。比上面的方法多占用162个字节

uint16_t val_in_EEPROM;    
#define updateEEPROMVal(address,val)  EEPROM.get(address,val_in_EEPROM); \
                                      if (val_in_EEPROM!=val)            \
                                        EEPROM.put(address,val)
void storeGlobalXYValsIntoEEPROM()
{
  uint16_t val_in_EEPROM;

  updateEEPROMVal(0,x_low);
  updateEEPROMVal(2,x_ctr);
  updateEEPROMVal(4,x_high);
  updateEEPROMVal(6,y_low);
  updateEEPROMVal(8,y_ctr);
  updateEEPROMVal(10,y_high);
}

感谢大家的帮助!

3)(更新的答案)EEPROM.put(address,val) 已经实现了我在上面试图实现的功能,以避免对 EEPROM 造成不必要的磨损,所以只需单独使用 .put() 函数,as-is!

参见

我又一次未能完整阅读文档。 EEPROM 库在此处放置函数文档 (https://github.com/arduino/Arduino/tree/master/hardware/arduino/avr/libraries/EEPROM) 说,"This function uses the update method to write its data, and therefore only rewrites changed cells." 因此,我的更新代码是多余的。我只需要使用 "put" 函数 as-is。也请在此处参考 EEPROM 库作者 (Chris A) 的回答。

所以,我学到了很多东西,这是我的最终答案:

去掉我的支持函数宏,只使用put函数as-is。它已经最大限度地减少了 EEPROM 磨损,并且仅在内容不同时才写入。不过,为了完整起见,我会为那些正在寻找宏或函数解决方案的人保留上面的答案。