5禁止的C功能

最佳实践和行业标准会随着时间的发展而发展,但它们代表了指导智慧的快照。尽管技术进步使先前已知的最佳实践无效,但最佳实践的发展速度可能很慢,而且往往会根深蒂固。在嵌入式系统空间中使用C语言功能遭受了同样的命运。许多最佳实践起源于80年代和90年代,那时编译器很古怪,而微控制器确实受到资源的限制。自那时以来,编译器和微控制器已经走了很长一段路,并且与它们一起使用的许多“禁止”功能和设计技术可能不再如此。

禁止字符拿着挂锁被隔绝在白色背景上

功能1 –浮动

在嵌入式系统中使用浮点数很长时间以来一直遭到强烈反对。传统上,浮法有很多潜在的问题根源。首先,微控制器没有浮点单元。对于大多数最低端的微控制器来说,今天的这种说法在很大程度上仍然适用,但是包含浮点单元(FPU)的成本已大大降低,以至中端和普通微控制器都开始包含FPU。微控制器技术的进步现在还包括用于数学函数的硬件加速,即使没有FPU也可以帮助加快计算速度。

其次,在不使用FPU的情况下使用float要求编译器引入笨重且缓慢的软件库。自20世纪末以来,编译器技术得到了极大的改进,即使在软件中的8位微控制器上执行浮点计算也被优化到可以忽略的程度。不相信我吗?试试看!结果会有所不同,甚至可能符合传统观念,但事实是技术正在发生变化,开发人员需要随之改变。

功能2 – malloc

Malloc允许开发人员在程序执行期间动态分配内存,当在嵌入式系统中使用不当时,它可能是非常危险的工具。传统上,出于充分的原因,在资源受限的系统中完全禁止使用malloc。当堆变成碎片时会发生什么?开发人员如何处理分配内存失败的问题?那内存泄漏呢?这些困难的程序需要代码空间和功能来处理传统微控制器无法处理的程序。

微控制器不再是“传统的”。 2015年一款低成本微控制器的时钟速度可能超过200 MHz,超过1 MB的闪存空间,RAM最高可达64 KB(高达256 MB)。即使在不够强大的系统中,也可以使用正确实现和使用malloc的工具。该应用程序也很可能需要保证,因此不应一开始就因为过时的最佳实践而将其排除在考虑范围之外。

功能#3 – printf

通常,在嵌入式系统中使用C库函数被认为是不明智的做法。大部分C库都不是可重入的,通常是笨重的并且执行缓慢(或者是?),或者以阻止执行直到完成的方式实现。 printf的使用属于这些类别中的许多类别,并且已避免在嵌入式系统中使用。嵌入式开发人员经常对使用printf感到内,或者在交谈中会说:“我不应该,但我添加了printf……”。

如前所述,已经发生了很多变化,并且在编译器优化和硬件改进之间,printf的使用曾经是一种罪恶感。考虑到典型的32 kB闪存空间,该功能虽然被认为是“大容量”,却只占用很少的代码空间。典型的实现是将printf用作阻止功能,这可能会影响实时响应并占用潜在的共享资源。通过将printf链接到循环缓冲区并中断驱动程序传输驱动程序,可以轻松解决响应问题,该驱动程序允许在驱动程序完成必要工作的同时继续执行程序。循环缓冲区有助于按先到先得的顺序保持消息顺序。

功能4 –记忆集

大多数涉及内存操作或动态内存的C功能最终都出现在禁止功能列表中。原因很明显,过去许多开发人员和团队都在使用这种功能。他们不再被烧毁,而是被移入了永不使用类别。当最好不要使用诸如malloc或memset之类的功能时,请尽量避免使用它们。相反,开发人员应确保他们完全了解如何使用该功能,正确使用所需的预防措施,在最坏的情况下如何恢复,当然还要进行适当的测试以确保一切均按计划进行。

功能#5 – C位字段

其用途不根植于编译器技术的进步或硬件的进步的一个概念是使用C标准中模棱两可的功能。这种功能的一个很好的例子是位域。使用位字段的最大问题是通常存在可移植性问题。一个简单的例子就是位排序不是标准的事实,并且编译器经常可以将位重新排列为它认为是最有效的实现方式。将填充字节添加到整个结构中还存在一些问题。

一般的经验法则是避免使用位字段,但是在很多情况下它们都是有意义的,甚至在可移植性问题都不重要的情况下也是如此。使用位字段的一个很好的例子是创建一个结构,该结构用于创建用于初始化驱动程序或应用程序的配置表。通过初始化读取位的值,重新排序甚至填充字节都不会成为问题。

结论

设计标准和最佳做法是为了帮助防止开发人员付诸东流,但这只是最佳做法。一个标准可能会说禁止使用C功能,但事实是,开发人员可以根据自己的独特情况来确定是否适用常规知识。挑战我们的先入之见,并确保我们了解为什么有这些最佳实践与遵循这些最佳实践一样重要。不要在不了解其应用,风险和收益的情况下注销这些功能。当考虑使用这些“禁止”功能时,开发人员需要了解他们的时间,性能和大小限制。

在当今的开发环境中,您还遇到了哪些其他功能可以正常工作,但通常被认为是禁止使用的?

3 thoughts 上 “5禁止的C功能”

  1. 记忆集: “大多数涉及内存操作或动态内存的C功能最终都出现在禁止功能列表中。原因很明显,”

    对我来说,为什么memset应该是一个特殊的问题并不明显。好的,如果涉及动态内存管理。否则,它类似于写入数组。您想确定没有其他人在写– but that’对内存集不是特别的。
    感谢您的澄清。

  2. 相当琐碎,但现在由C编译器处理,而过去则没有。
    由于使用的常见错误,例如
    ‘ if (x = const)’ instead of ‘ if (x== const)’

    建议使用‘if (const == x)’这样的错误– ‘if (const = x)’在编译时会被拾取。
    但是,当前的C编译器会拾取该错误& flag a warning for
    ‘if (x= const)’, so it’与哪个值先行无关。

  3. 1)浮子在许多控制应用中很有用。只要您注意:
    –不比较浮点数是否相等(即,您应该始终这样做>= or <= and never ==).
    – Making sure you don'将一个小数字加到一个大数字上(您很快就会失去分辨率)。

    正如您指出的那样,更多的MCU配备了FPU,这使使用寿命大大简化。我认为使用浮点数比比例算术更不容易出错。

    2)如果您不使用malloc()可以't free()。我仍然相信您应该避免使用malloc(),因为无论您有多少RAM,都会发生碎片(很可能在现场,而不是实验室)。

    3)我不't喜欢使用printf()因为它'通常是笨重的,不确定的,并且会影响嵌入式系统的时序。如果在RTOS环境中使用,则必须注意重入。一些编译器实现了线程本地存储,但是RTOS在上下文切换期间需要考虑这一点。

    4)memset()很好,但是非常针对编译器,因为其实现是针对工具供应商的。不过,编译器供应商通常会优化memset()。

    5)位域,我不知道'记得曾经用过那些。也许是因为几年前有人建议它们不可移植,因此您需要对“读取-修改-写入”有所了解。

发表评论

您的电子邮件地址不会被公开。 必需的地方已做标记 *

该网站使用Akismet减少垃圾邮件。 了解如何处理您的评论数据.