Arduino 优化指南

76 阅读1分钟

类属性尽量不要独立写 .cpp 文件

问题本质是“函数分离导致链接器过度保留 .o 文件”。最优解是把该函数实现挪进头文件并加 inline

正确写法:

// esp-ai.h
class ESP_AI {
public:
    inline void onBegin(bool (*func)()) {
        onBeginCb = func;
    }

private:
    bool (*onBeginCb)() = nullptr;
};

字符串形参尽量用 const String&

可以保证变量的安全性,也不会重复复制字符串。

正确写法:

    void onSessionStatus(void (*func)(const String &status));
用法内存消耗推荐说明
String动态内存,容易碎片
const char*编译期常量,或者栈变量
snprintf + buf控制好大小即可

任务用 xTaskCreateStatic,并且不要试图传入某个类的属性

正确写法:

xTaskCreateStatic(light_task_static, "lights", 512, &light_ctx, 1, lightsTaskStack, &lightsTaskBuffer);

错误写法:

xTaskCreate(ClassName::play_audio_wrapper, "play_audio", 1024 * 2, this, 1, NULL);

头文件中如果不直接使用第三方类时使用前向声明

🧠 什么时候可以使用 forward declare?

使用场景是否可以 forward declare
只声明指针或引用 Foo*✅ 可以
不需要访问 Foo 的成员变量✅ 可以
需要 new Foo().bar()❌ 不可以,需要完整类定义
定义成员变量 Foo foo;❌ 不可以,必须 include
#pragma once

// 不包含大库,使用前向声明代替 #include
class DriverPins;
class AudioBoard;
class I2SCodecStream;
template <typename T> class QueueStream;         // ✅ 模板类的前向声明需写成这样
class EncodedAudioStream;
class TwoWire;                                  

// 结构体定义:保留字段但注释掉以测试内存差异
struct SpeakerI2SContent {
    DriverPins *esp_ai_audio_pins;
    AudioBoard *esp_ai_audio_board;
    I2SCodecStream *esp_ai_spk_i2s;
    QueueStream<uint8_t> *esp_ai_spk_queue;
    EncodedAudioStream *esp_ai_dec;
    TwoWire *esp_ai_audio_wire;
};

// 函数声明
void speaker_i2s_setup(SpeakerI2SContent *content);