为什么嵌入式 C++ 编译器不支持异常?

Why Embedded C++ compilers not support exceptions?

我正在为嵌入式系统编写一个库,但我遇到了没有容易找到的 STL 标准库。

但我收到的最糟糕的消息是编译器没有异常支持。 Atmel参考手册显示this

嵌入式环境为什么不支持异常?

使用大量用 C++ 编写的库很简单,无法使用。 C++ 与异常密切相关,例如 new 运算符!

显然,除了开发该编译器的人之外,没有人能真正回答这个问题。

我最好的猜测是异常是 space- 和 time-consuming(当代码抛出时时间只是一个真正的问题,但是展开表总是需要 space ,并且很容易与编译代码的整体代码大小相同),加上 "rather difficult to implement",对于编译器开发人员来说,它可能不是列表中最高的项目,因此尚未实现。是否会在未来的某个时候显然取决于 Atmel 或他们分包制造编译器的任何人。

我不是 Atmel C++ 实现方面的专家,但如果编译器支持 throw 但不支持 try/catch,我会感到非常惊讶 - 因为那将和螺丝刀一样有用由巧克力制成,当试图在完全加热的桑拿房中修理加热器时。

如果您使用 -fno-exceptions,如果代码中有任何 throw,编译器应该会出错。 STL 可以用 -fno-exceptions 编译——因为我就是这样编译我的编译器代码的。

8 位 AtmelAVR 及其有限的 ROM 和 RAM 资源不适合使用对两者都施加相当大负载的 STL。此外,C++ 异常本质上是 non-deterministic,因此不适合许多 real-time 应用程序。

编译器可以实现 EC++(嵌入式 C++)"standard"。 EC++ 的目标有两个:

  • 通过将语言限制为所有编译器都可用的通用子集,在语言的 ISO 标准化之前支持在嵌入式系统中使用 C++。
  • 避免non-deterministic(在内存和时序方面)language/library 不适合硬real-time 应用程序的功能。

EC++ 中缺少的内容包括:

  • 命名空间
  • 模板
  • RTTI
  • 例外情况

命名空间的省略完全取决于 EC++ 的第一个目标,现在基本上已经过时了。两个目标都证明了其他人的遗漏是合理的,并且排除了 STL 和 std::string 库的使用。

EC++ 本身现在已基本过时,但它定义的子集仍然适用于资源严重受限的目标,并且许多编译器支持全部或部分 EC++ 实施。

请注意,也许并非所有 AVR 编译器都会施加这些限制,但如果您尝试广泛使用这些功能,您可能很快就会发现为什么在大多数情况下不建议在非常有限的目标 CPU 和内存上使用它们资源。

关于 new 运算符的使用,默认动态内存分配(与 placement new 或覆盖相对)本质上是 non-deterministic 并且通常最好避免在 real-time 嵌入式系统中使用,尤其是在可用最小堆的情况下。要在不假设异常处理的情况下使用 new,请使用 new (std::nothrow) (#include <new>),它不会抛出异常但 return 像 malloc() 这样的空指针。在 EC++ 中,newnew (std::nothrow) 本质上是同一件事,但后者是可移植的和显式的。

在 Atmel 为 GCC-AVR 维护的 open-source 库中缺少对 C++ 的支持并不意味着通常不支持嵌入式系统,或者实际上不支持 AVR。 IAR 的 AVR 编译器支持它所称的扩展嵌入式 C++ (EEC++) 以及 EC++。 EEC++ 确实支持包括 STL 的 C++ 库,并进行了一些修改——没有 RTTI,没有异常,并且不在 std:: 命名空间中(尽管支持命名空间)。与大多数 32 位目标上的 EC++ 相比,对 ISO C++ 的支持通常更全面。