Arduino代码本质是C++,.ino文件经IDE预处理后成为标准C++,支持类、String等特性,但需规避RTTI、异常、未初始化变量等AVR平台限制。

Arduino默认就是用C++写的,不是“怎么用”,而是你已经在用了——setup()和loop()本身就是C++函数,Serial、digitalWrite这些全是C++对象或全局函数。关键在于:别被“.ino”后缀骗了,它会被IDE自动预处理成标准C++文件。
为什么写出来的.ino文件能当C++用?
Arduino IDE在编译前会做两件事:setup()和loop()自动声明为void setup(); void loop();;所有全局变量和函数定义自动提至文件顶部(即隐式加了函数原型)。这意味着你不用手动写#include 或声明函数,但底层完全是C++语法支持的。
常见误解是以为.ino = C语言,其实它比C更宽松:允许在函数外直接定义类、使用String、std::vector(需手动包含)、甚至lambda(在较新板型+Core 3.0+下可用)。
想用C++特性,必须绕开哪些坑?
Arduino官方Core(尤其是AVR系如Uno/Nano)默认不启用RTTI和异常,new/delete也受限(堆空间极小),所以以下操作要特别注意:
-
dynamic_cast、typeid、throw/catch—— 编译会失败,除非手动改platform.txt并接受体积/性能代价 - 未初始化的类成员变量 —— AVR平台不保证零初始化,
int x;在类里可能是随机值,必须显式写x{0}或:x(0) - 模板过度展开 —— 比如嵌套
std::function+lambda,容易触发编译器内存溢出或生成超大二进制 - 忘记
virtual析构函数 —— 若基类指针指向派生类对象(如Device* d = new LedDriver;),delete d不会调用派生类析构,资源泄漏
实际项目中推荐的C++写法
不是炫技,而是让代码可维护、可复用。比如控制多个LED,别再复制粘贴delay()逻辑:
class Blinker {
private:
const uint8_t pin_;
unsigned long interval_;
unsigned long last_toggle_;
bool state_;
<p>public:
Blinker(uint8<em>t p, unsigned long ms) : pin</em>(p), interval_(ms), last<em>toggle</em>(0), state<em>(LOW) {
pinMode(pin</em>, OUTPUT);
}</p><p>void update() {
if (millis() - last<em>toggle</em> >= interval<em>) {
state</em> = !state<em>;
digitalWrite(pin</em>, state_);
last<em>toggle</em> = millis();
}
}
};</p>
然后在loop()里只写:
Blinker led1(2, 500);
Blinker led2(3, 1200);
<p>void loop() {
led1.update();
led2.update();
}</p>
这种写法避开了delay()阻塞,天然支持多任务节奏,且每个实例状态完全隔离——这才是C++在Arduino上最实在的价值。
真正难的不是语法,而是克制:AVR只有2KB RAM,一个String拼接三次就可能崩;ESP32虽强,但WiFi库内部大量动态分配,new之后没配delete,几天就OOM。C++在这里不是自由,是带着镣铐的精准控制。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











