C预处理器如何字符串化含扩展字符(如°)的字符串?
解决Arduino宏字符串化含特殊扩展字符的编译报错问题
问题根源在于avr-gcc的预处理器在处理#__VA_ARGS__字符串化宏时,会将传入内容按C标识符规则解析,而°、¿、¡、«、»这类字符不在合法标识符字符范围内,因此触发报错。以下是几种可行的解决方法:
方案1:使用C++原始字符串字面量(推荐)
avr-gcc 12.2.0支持C++11及以上标准,原始字符串字面量可直接包含特殊字符,无需转义,同时完美兼容条件编译和PROGMEM的RAM节省需求:
#include <Arduino.h> // 按硬件类型切换不同HTML内容 #if defined(DEVICE_SENSOR_A) const char htmlRootPage[] PROGMEM = R"(<input name="txtGt" type="number" value="39.5" max="42" step="0.5" style="width:160px;">°C<br>)"; #elif defined(DEVICE_SENSOR_B) const char htmlRootPage[] PROGMEM = R"(<input name="txtGt" type="number" value="98.6" max="104" step="0.1" style="width:160px;">°F<br>)"; #endif void setup() {} void loop() {}
原始字符串用R"(...)"包裹,内部特殊字符直接书写即可,预处理器不会将其当作标识符解析,彻底避开报错,且代码可读性极强。
方案2:转义特殊字符为UTF-8十六进制序列
将报错的特殊字符替换为对应的UTF-8字节转义码,比如:
°→\xC2\xB0¿→\xC2\xBF¡→\xC2\xA1«→\xC2\xAB»→\xC2\xBB
修改后的代码示例:
#include <Arduino.h> #define TOSTR_(...) #__VA_ARGS__ #define STRINGIFY(...) TOSTR_(__VA_ARGS__) const char htmlRootPage[] PROGMEM = STRINGIFY(<input name="txtGt" type="number" value="39.5" max="42" step="0.5" style="width:160px;">\xC2\xB0C<br>) ; void setup() {} void loop() {}
转义序列属于合法的字符串内容,预处理器解析时不会触发标识符错误。
方案3:拆分字符串拼接
把含特殊字符的部分单独定义为PROGMEM字符串,再和宏字符串化的内容拼接,绕过预处理器的标识符检查:
#include <Arduino.h> #define TOSTR_(...) #__VA_ARGS__ #define STRINGIFY(...) TOSTR_(__VA_ARGS__) const char degreeSymbol[] PROGMEM = "°"; const char htmlRootPage[] PROGMEM = STRINGIFY(<input name="txtGt" type="number" value="39.5" max="42" step="0.5" style="width:160px;">) degreeSymbol STRINGIFY(C<br>) ; void setup() {} void loop() {}
注意这种方式会生成多个独立的PROGMEM字符串,使用时需额外处理拼接逻辑,仅适合无法使用前两种方案的场景。
内容的提问来源于stack exchange,提问作者user2718593
相关产品推荐
相关产品推荐

