如何使普通的C库在嵌入式环境下工作?

时间:2019-06-20 03:08:26

标签: embedded

最近有人问我如何在嵌入式环境中使用C库(在这种情况下为Cello),但是我不确定该怎么做。

如果可以在嵌入式环境中编译库,是否可以使用它是正确的说法吗? 我是否应该关心使库更轻巧或类似?

任何建议都值得赞赏。

2 个答案:

答案 0 :(得分:2)

要编译它是最低要求。值得注意的是,大多数嵌入式系统都是独立系统,例如微控制器和RTOS应用程序。独立系统的编译器不需要提供所有标准库头,唯一的必需是(C17 4/6):

<float.h>, <iso646.h>, <limits.h>, <stdalign.h>, <stdarg.h>, <stdbool.h>, 
<stddef.h>, <stdint.h>, <stdnoreturn.h>

此外,嵌入式系统不需要支持浮点运算。一些系统实现了软件浮点支持,但是使用它是非常不好的做法。如果您的MCU没有FPU,则不应使用浮点运算,或者在任务期间选择了错误的MCU。

“我需要在内部或对用户使用小数表示此数字”不是使用浮点数的有效理由。为此,应使用定点算法。如果要使用诸如math.h之类的数学库和更高级的数学,则需要浮点数。

传统上,嵌入式系统编译器在适应最新的C标准方面进展缓慢。但是自从C11发布以来已经有一段时间了,所以目前所有有用的编译器都赶上了它(C17仅包含较小的更改,因此我们可能会忽略该更改)。从历史上看,嵌入式编译器在这方面一直非常糟糕,因此请保持怀疑。应该没有任何理由选择没有C11支持的编译器来开发新产品。

使lib编译的摘要(最低要求):

  • 该库是否使用托管系统头,如果是,嵌入式编译器是否支持它们?
  • 库是否使用浮点数?如果是,目标系统是否具有FPU或至少一个软件浮点库?
  • 该库是否依赖最新的C标准,如果是,嵌入式编译器是否支持它们?

这样一来,您就必须考虑该库是否是为可移植而编写的。他们是否照顾整数类型,枚举和对齐方式?他们在各处使用stdint.h还是在使用“草率键入” int?他们是否考虑了耐力? lib是否使用动态分配(在大多数嵌入式系统中都被禁止)?它与MISRA-C等行业标准兼容吗?依此类推。

然后在此基础上考虑优化。为微控制器优化代码与为PC CPU优化代码大不相同。

简要浏览当前出现的各种“编译器开关”(#ifdef),通常可以得出代码的可移植性的线索。 (非常简要地)看一下这个大提琴库,他们似乎已经考虑过在主流x86系统之间进行移植,仅此而已。如果要将其移植到嵌入式系统,则几乎必须重写整个lib。工作量取决于将目标CPU与x86进行比较的方式。使用Little Endian移植到高端Cortex-A可能不需要太多工作。移植到一些低端的废话MCU上需要付出巨大的努力。

代码可移植性是一个大话题,需要非常称职的C程序员。要使相同的代码在x86-64和笨拙的8位MCU上运行,并不是一件容易的事。

像协议栈之类的专业库通常带有特定MCU的系统端口,在这些端口中,它们不仅考虑了通用可移植性,而且还考虑了特定系统。

答案 1 :(得分:1)

并非所有可以编译的库都可以在嵌入式环境中使用。使用mallocfree(或其C ++副本)的库很危险,因此应谨慎处理。由于内存分配失败,这些库可能导致不确定的行为。

可能可以为嵌入式设备完全编译标准C STD,但这并不意味着您将对printfscanf有很多用途。因此,在问是否可以编译之前,一个更好的问题是是否应使用。大提琴似乎是一个有趣的实验,但并不是一个稳定的平台,无法在其上进行实际开发。不过可以做到,Espruino就是一个例子。

在大多数情况下,将库重写为“轻量级”或更重要的是在嵌入式环境中是一个坏主意:静态分配。您可能不像那些人那么聪明,或者您不会花费时间来创建功能完整的嵌入式分叉,该分叉与原始分叉一样稳定,甚至更好。不要为一个有趣的小项目而劝阻,但不要为一个真实的项目而依赖它。

另一个问题可能是该库对于您的微控制器而言太大。 Atmega32a只有32KB的可编程闪存。举一个我脑海中的C ++例子:即使对于它提供的所有高度可用的工具,boost也不适合这个空间。