【问题标题】:Developing embedded software library, C or C++?开发嵌入式软件库,C 还是 C++?
【发布时间】:2010-01-14 15:59:20
【问题描述】:

我正在开发一个用于嵌入式系统的软件库,如 ARM 芯片或 TI DSP(主要用于嵌入式系统,但如果它也可以用于 PC 环境中也会很好) )。显然,这是一个相当广泛的目标系统,因此能够轻松移植到不同的系统是一个优先事项。该库将用于与特定硬件的接口并运行一些算法。

我认为 C++ 是优于 C 的最佳选择,因为它更易于维护和阅读。我认为额外的开销是值得的,因为它能够在面向对象的范式中工作。如果我正在为一个非常具体的系统编写代码,我会在 C 中工作,但事实并非如此。

我假设现在大多数流行的嵌入式系统的编译器都可以处理 C++。它是否正确?

还有其他我应该考虑的因素吗?我的思路对吗?

【问题讨论】:

  • “流行的嵌入式系统”... x86、ARM、MSP430、AVR、8051、PIC。这是一个很大的能力范围。 C++ 不太适用于规模的低端。
  • 这个问题在两年前被问到时可能更容易接受,但现在一般不鼓励这样的主观问题。也就是说,看起来我们并没有因此而引发任何激烈的战争;大家干得好!

标签: c++ c embedded


【解决方案1】:

如果可移植性对您来说非常重要,尤其是在嵌入式系统上,那么 C 肯定是比 C++ 更好的选择。虽然嵌入式平台上的 C++ 编译器正在迎头赶上,但 C 的广泛使用根本无法与之匹敌,任何自尊的平台都有兼容的编译器。

此外,我认为 C 在连接硬件方面并不逊于 C++。抽象的数量足够低(即没有深层的类层次结构),使 C 成为一个不错的选择。

【讨论】:

    【解决方案2】:

    C++ 对 ARM 的支持当然很好。 ARM 有自己的编译器,g++ 也可以生成符合 EABI 的 ARM 代码。当谈到 DSP 时,您将不得不查看他们的工具链来决定您要做什么。请注意,DSP 附带的库可能无法实现完整的 C 或 C++ 标准库。

    C++ 适用于低级嵌入式开发,用于 SymbianOS Kernel。话虽如此,您应该使事情尽可能简单。

    • 避免可能需要比现有更多库支持的异常(因此使用 new (std::nothrow) Foo 而不是 new Foo)。
    • 尽可能避免内存分配并尽早进行。
    • 避免复杂的模式。
    • 请注意,模板会使您的代码膨胀。

    【讨论】:

    • 许多 C++ 编译器都有禁用异常和禁用运行时类型识别的选项。这两种方法通常都是编译嵌入式应用程序的好选择(除非您专门使用该语言的这些部分——并且由于代码大小的成本,您应该在这样做之前仔细考虑)。
    • 另外,说“模板会使你的代码膨胀”有点误导恕我直言。一旦成为机器代码中的许多实例化,它们就是编写一些源代码的一种方式。当然,这是一个需要小心使用的工具,但当它完全按照它应该做的事情时,它并不是什么神秘的“膨胀”。 (不过,回到第一手,我听说过编译器的代码过大,模板做得不好,所以我想你还是有道理的!)
    • 我之前使用过“瘦”模板概念。在这里,您创建了一个通用的不安全类(例如一个 void* 指针容器)并使用模板稍后添加类型安全。如果所有函数都内联,则模板实例化不应影响代码大小。
    【解决方案3】:

    我看到很多抱怨 C++“臃肿”且不适合嵌入式系统。

    但是,在接受 Stroustrup 和 Sutter 采访时,Bjarne Stroustrup 提到,他看到大量模板化的 C++ 代码进入 (IIRC) 宝马的制动系统以及战斗机的导弹制导系统。

    我从中得出的结论是,该语言的专家可以用 C++ 生成最适合嵌入式系统的复杂、高效的代码。但是,一个完全不了解该语言的“带类的 C”[1] 程序员会生成不合适的臃肿代码。

    与往常一样,问题归结为:您的团队可以使用哪种语言提供最好的产品?

    [1] 我知道这听起来有点贬义,但我要说我认识很多这样的人,他们编写了大量相对简单的代码来完成工作。

    【讨论】:

    • 战斗机的导弹制导系统——当然他们不会告诉你太多关于膨胀与否的信息。我想他们宁愿多花几美元买更多的内存。
    • 现在我想起来了,我相信战斗机这件事更像是展示了 C++ 是如何在关键任务软件中使用的。不过,BMW 位绝对是关于嵌入式系统的。
    【解决方案4】:

    用于嵌入式平台的 C++ 编译器比 98 的 C++ 标准更接近 83 的 C,更不用说 C++0x。例如,我们使用的某些平台仍然使用由 gcc-2.95 制成的特殊版本的 gcc 进行编译!

    这意味着您的库接口将无法提供具有容器/迭代器、流或此类高级 C++ 功能的接口。您必须坚持使用简单的 C++ 类,这些类可以很容易地表示为 C 接口,并将指向结构的指针作为第一个参数。

    这也意味着在您的库中,您将无法充分利用模板。如果你想要可移植性,你仍然会被限制在通用容器中使用模板,我相信你会承认,这只是 C++ 模板功能的一小部分。

    【讨论】:

    • 在某些情况下确实如此,但在其他情况下则远非如此(例如典型的 ARM 平台)。
    【解决方案5】:

    如果在嵌入式环境中正确使用,C++ 与 C 相比几乎没有开销。 C++ 在信息隐藏、OO 等方面有很多优势。如果你的嵌入式处理器被 C 中的 gcc 支持,那么它很可能也会被 C++ 支持。

    【讨论】:

      【解决方案6】:

      在 PC 上,C++ 根本不是问题——高质量的编译器非常普遍,几乎每个 C 编译器都直接与一个相当不错的 C++ 编译器相关联,但也有一些例外,例如 lcc 和新复兴的 pcc。

      基于 ARM 的大型嵌入式系统在工具链可用性方面通常与桌面系统非常相似。事实上,许多可用于桌面机器的相同工具也可以生成代码以在基于 ARM 的机器上运行(例如,它们中的许多使用 gcc/g++ 端口)。 TI DSP 的种类较少(并且更强调生成代码的质量而不是源代码功能),但仍然至少有几个受人尊敬的 C++ 编译器可用。

      如果您想使用较小的嵌入式系统,情况会很快发生变化。如果您希望能够针对 PIC 或 AVR 之类的东西,C++ 并不是一个真正的选择。理论上,您可以(例如)让 Comeau 生成一个自定义端口,该端口生成可以在该目标的 C 编译器上编译的代码——但很有可能即使您这样做了,它也不会很好地工作。这些系统实在是太有限了(尤其是内存大小),C++ 无法很好地适应它们。

      【讨论】:

        【解决方案7】:

        根据您对该库的预期用途,我认为我建议首先将其实现为 C - 但设计应牢记如何将其合并到 C++ 设计中。然后在 C 实现之上和/或旁边实现 C++ 类(没有理由不能与第一步同时完成此步骤)。如果您的 C 设计是在考虑 C++ 设计的情况下完成的,那么它可能与 C++ 设计一样干净、易读和可维护。这需要更多的工作,但我认为您最终会得到一个在更多情况下有用的库。

        虽然您会发现 C++ 在各种嵌入式项目中的使用越来越多,但仍然有许多将自己限制在 C 中(我猜这种情况更多见)——无论这些工具是否支持C++。拥有一个很好的例程库,您可以将其带到您正在从事的新项目中,但由于该特定项目未使用 C++ 而无法使用它们,这将是一种耻辱。

        一般来说,从 C++ 中使用精心设计的 C 库比使用其他方式要容易得多。我已经在几组代码中采用了这种方法,包括解析 Intel Hex 文件、一个简单的命令解析器、操作同步对象、FSM 框架等。我计划在某个时候做一个简单的 XML 解析器。

        【讨论】:

          【解决方案8】:

          这是一个完全不同的 C++-vs-C 论点:稳定的 ABI。如果您的库导出 C ABI,则可以使用在系统上运行的任何编译器对其进行编译,因为 C ABI 通常是平台标准。如果您的库导出 C++ ABI,则只能使用匹配的编译器对其进行编译——因为 C++ ABI 通常不是平台标准,并且通常因编译器而异,甚至因版本而异。

          有趣的是,ARM 是罕见的例外之一。有一个 ARM C++ ABI 规范,所有兼容的 ARM 编译器都遵循它。这在 x86 上是不正确的;在 x86 上,如果使用 4.1 版本的 GCC 编译的 C++ 库能够正确链接到使用 GCC 4.4 编译的应用程序,那么您就很幸运了,甚至不用询问 3.4.6。

          即使您导出 C ABI,也可能会遇到问题。如果您的库在内部使用 C++,那么它将链接到 libstdc++ 以获取 C++ std:: 命名空间中的内容。如果您的用户编译使用您的库的 C++ 应用程序,他们还将链接到 libstdc++ - 因此整个应用程序会链接到 libstdc++ 两次,并且他们的 libstdc++ 可能与您的 libstdc++ 不兼容,这可以(或者我理解) 导致两者相交的奇怪错误。可能性大大降低,但仍有可能。

          所有这些论点适用,因为您正在编写一个库,而它们不是炫技。但它们是需要注意的事情。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2016-06-20
            • 2021-01-26
            • 1970-01-01
            • 1970-01-01
            • 2016-09-30
            • 1970-01-01
            • 2010-10-23
            相关资源
            最近更新 更多