嵌入式 C++:是时候抛弃 C 语言了吗?

Evek Golden Lv4

“C++ 产生的代码太大了”、”C++ 虚函数太慢了” —— 这些对 C++ 的刻板印象在嵌入式圈子里流传甚广。但事实上,这往往是因为我们将 PC 端的 C++ 习惯(如大量使用 STL、异常、RTTI)带入到了嵌入式开发。

现代 C++ (C++11/14/17/20) 提供了大量**零开销抽象 (Zero-cost Abstractions)**,让我们既能享受高级语言的便利,又不会损失一丁点性能。

1. 零开销的寄存器操作

在 C 语言中,我们通常用宏来操作寄存器:

1
2
#define GPIOA_ODR (*(volatile uint32_t *)0x48000014)
GPIOA_ODR |= (1 << 5); // 没有任何类型检查

在 C++ 中,我们可以使用模板和结构体来实现类型安全的操作,编译后的汇编代码与 C 完全一致:

1
2
3
4
5
6
7
8
9
10
11
template<uint32_t addr>
struct Reg {
static void setBit(int bit) {
*(volatile uint32_t *)addr |= (1 << bit);
}
};

using GPIOA_ODR = Reg<0x48000014>;

// 调用
GPIOA_ODR::setBit(5);

这不仅防止了把 GPIOA 赋值给 UART 的低级错误,还能通过 IDE 获得完美的自动补全。

2. const vs constexpr

C 语言的 const 只是只读变量,它还是会占用 RAM(或 Flash),且不能用于定义数组大小。

C++ 的 constexpr编译期常量

1
2
3
4
5
6
constexpr int fib(int n) {
return (n <= 1) ? n : fib(n-1) + fib(n-2);
}

// 编译时直接计算出结果,运行时直接把结果填进去,零 CPU 消耗
int val = fib(10);

3. nullptr 与 enum class

  • nullptr: 解决了 NULL 到底是 0 还是 (void*)0 的歧义,防止了整数和指针的隐式转换。
  • enum class:
    1
    2
    enum class Color : uint8_t { Red, Green, Blue };
    // Color c = 1; // 编译报错!必须显式转换
    强制类型检查,且可以指定底层数据类型(如 uint8_t),省内存。

4. RAII 管理资源

在嵌入式中,记得释放资源(关中断、释放锁、关文件)是很难的。C++ 的构造/析构函数可以自动管理这些。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class LockGuard {
public:
LockGuard(Mutex& m) : m_(m) { m_.lock(); }
~LockGuard() { m_.unlock(); }
private:
Mutex& m_;
};

void task() {
{
LockGuard lock(myMutex); // 自动上锁
// 做一些临界区操作...
} // 出了作用域,自动解锁!永远不会忘
}

结论

我们不需要全盘接受 C++。只要禁用掉 Exceptions (异常)RTTI (运行时类型识别) 和 **Heap (如果可能)**,C++ 就是一个类型更强、表达力更强、且同样高效的 “C With Classes”。

  • Title: 嵌入式 C++:是时候抛弃 C 语言了吗?
  • Author: Evek Golden
  • Created at : 2025-04-02 23:00:00
  • Updated at : 2026-06-12 08:57:02
  • Link: https://blog.cocodemo.uno/posts/cpp9k4d/
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments