在嵌入式开发中,使用C语言而不是C++是否有任何理由?

97

问题

我在我的硬件上有两个编译器,分别是C++和C89。

我正在考虑使用带类但不使用多态性(以避免虚函数表)的C++。 我想使用C++的主要原因是:

  • 我更喜欢使用“inline”函数而不是宏定义。
  • 我想使用名称空间来避免代码混乱。
  • 我认为C++更加类型安全,主要是因为有模板和详细的强制类型转换。
  • 我真的很喜欢重载函数和构造函数(用于自动转换)。

您认为在为非常有限的硬件(4KB RAM)开发时坚持使用C89有任何理由吗?

结论

感谢您的回答,它们非常有帮助!

我经过深思熟虑,决定坚持使用C,主要是因为:

  1. 在C中更容易预测实际代码,如果只有4KB RAM,这非常重要。
  2. 我的团队主要由C开发人员组成,因此不会经常使用高级的C ++功能。
  3. 我已经找到了一种方法,在我的C编译器(C89)中内联函数。

很难接受一个答案,因为您提供了许多好的答案。不幸的是,我无法创建维基并接受它,因此我将选择一种让我思考最多的答案。


13
一件事情:始终要清楚地知道你正在使用哪种语言进行编写。不要试图用“C/C++”来编写程序。要么使用C编写,要么使用C++编写,并明确知道你将使用哪些语言特性以及哪些不会使用。 - David Thornley
1
请参见https://dev59.com/c3RB5IYBdhLWcg3wWGEH - Suma
1
@DavidThornley,对于嵌入式案例你可能是正确的,但我非常惊讶地发现,在我试图通过STL扩展常见的行业开源应用程序(如Kamailio)时,混合使用C和C++代码非常不错。我正式鼓励这种使用STL和C代码,因为它提供了巨大的功能和易于维护,同时几乎不会产生任何问题(C++中缺少嵌套结构体是一种可怕的犯罪,应该尽快改正)。 - user2548100
思考的食物,这是一篇很棒的文章,其中ZeroMQ的设计师和作者讨论了他为什么后悔使用C++而不是C编写代码库。这并不是我预期的,原因在此页面上也没有找到。http://250bpm.com/blog:4 - user2548100
嗯,确实如此。匿名结构体就是它了。 - user2548100
显示剩余3条评论
29个回答

1
对于内存分配问题,我建议使用量子平台及其状态机方法,因为它在初始化时分配了您所需的所有内容。 它还有助于缓解争用问题。
该产品可在C和C ++上运行。

1
一些人认为 C 编译器可以生成更高效的代码,因为它们不必支持高级的 C++ 特性,因此可以在优化方面更加激进。
当然,在这种情况下,您可能想要对这两个特定的编译器进行测试。

1
相关:据我所知,restrict关键字是C++(包括C++11)中唯一缺少的与优化相关的C构造。 - Johan Lundberg

1
在我看来,只有当你的平台上的C++编译器存在问题(有bug、优化差等)时,才会选择C语言。

内存/资源利用情况如何? - Steve Lazaridis
它有什么问题吗?C++编译器产生的代码比C编译器低效的原因是没有理由的,除非代码使用RTTI,在嵌入式系统上没有人这样做。 - Nemanja Trifunovic

1

你在C99中使用了内联函数。也许你喜欢构造函数,但确保正确处理析构函数的业务可能会很混乱。如果不使用C的唯一原因是命名空间,我建议您仍然坚持使用C89。这是因为您可能希望将其移植到稍微不同的嵌入式平台上。您可以稍后在相同的代码上开始使用C ++。但请注意,C ++并不是C的超集。我知道你说你有一个C89编译器,但是这个C ++与C99的比较还是适用的,例如第一个条目对于自K&R以来的任何C都是正确的。

'a'的大小在C中> 1,在C++中不是。 在C中,您具有可变长度数组(VLA)。示例:func(int i){int a [i] }。 在C中,您具有可变数组成员(VAM)。示例:struct {int b; int m [];}


在C语言中,sizeof 'a' > 1是什么意思?最新的C标准是否使用宽字符? - Piotr Czapla
1
不,我的意思是在 C 语言中你有 (sizeof 'a') == sizeof(int)。而在 C++ 中你有 1 == sizeof 'a'。 - hept
1
更不用说“int * a; ...;a = (int *)malloc(size * sizeof(int));”这种在C和C++中都能工作的分配内存的方式,实际上两者都不应该使用。相反,应该使用“a = malloc(size * sizeof(int));”或“vector<int> a(size);”,甚至是“int * a = new int[size];”。 - David Thornley
1
我不明白你关于dtors的观点。它们的整个意义在于使你的代码变得更加简洁。 - jalf
1
不确定为什么这篇文章会被评价得如此糟糕。但我同意jalf的观点,当以正确的方式(RAII)使用时,析构函数可以极大地简化代码。(你可以说它们“在幕后工作”,但它们只是在做正确的代码本来就要手动完成的事情。) - j_random_hacker
1
我认为我指出的东西非常相关于这个问题。我还坚持我的观点,即析构函数可能很困难,原因正是它会自动发生。我得了负分——真的很苛刻。我想这是因为我没有说“是的,使用C++很棒”。 - hept

1

这取决于编译器。

并非所有嵌入式编译器都实现了C++的所有内容,即使它们实现了,它们也可能不擅长避免代码膨胀(使用模板时始终存在的风险)。使用一些较小的程序进行测试,看看是否遇到任何问题。

但是,如果使用的编译器,没有理由不使用C++。


1
我建议使用 C++,但需要注意一些限制。
  1. 上市时间和可维护性。 C++开发更容易更快速。因此,如果您处于设计阶段,请选择一个足够强大的控制器来使用C++。(请注意,一些高销量市场要求尽可能低成本,在这种情况下,您不能做出这个选择。)

  2. 速度。 C语言可能比C++更快,但请确保速度提升不是很大。因此,您可以选择C++。开发算法,测试它们,并仅在必要时使它们更快!使用分析工具指出瓶颈并以"extern "C"方式重写它们,以实现C语言的速度。(如果仍然很慢,请使用汇编语言实现该部分)

  3. 二进制文件大小。 C++代码较大,但这里有一个很好的答案详细说明了情况。给定C代码的编译后二进制文件大小将是相同的,无论是使用C还是C++编译器进行编译。"可执行文件大小与语言几乎无关,而与您在项目中包含的库有关。"选择C++,但避免使用高级功能,如streamsstringnewvirtual函数等。在让库函数进入最终代码之前,请审查所有库函数,因为存在大小限制(基于this答案)


0

全球有许多不同的控制器制造商,当您深入了解它们的设计和需要使用的指令集进行配置时,可能会遇到很多麻烦。汇编语言的主要缺点是机器/架构依赖性。对于开发人员来说,要记住所有指令集以完成不同控制器的编码是一个巨大的挑战。这就是为什么C在嵌入式开发中变得更加流行的原因,因为C足够高级,可以将算法和数据结构从硬件相关细节中抽象出来,使源代码可在各种目标硬件上移植,具有架构无关性的语言,并且非常容易转换和维护代码。但是我们确实看到一些高级语言(面向对象)如C、C++、Python、Java等正在不断发展,使它们成为嵌入式系统开发的重点。


0

回答问题的不同方面:

"malloc"

之前的一些回复已经对此进行了详细的讨论。你为什么觉得需要这个调用?对于真正小型的平台,malloc往往是不可用的,或者说是可选的。实现动态内存分配往往在底层系统中使用RTOS才有意义,但在那之前,它纯粹是危险的。

您可以在没有它的情况下走得很远。只需想想所有旧的FORTRAN程序,它们甚至没有适当的堆栈来存储本地变量...


-6
在这样一个有限的系统上,最好使用汇编语言。它可以让你完全控制每个方面,并且没有额外的开销。
可能会更快,因为很多嵌入式编译器并不是最好的优化器(特别是与我们为桌面开发的最先进的编译器相比,如英特尔、Visual Studio等)。
“是啊是啊……但C语言是可重用的……”。在这样一个有限的系统上,你很可能不会在另一个系统上重复使用大量代码。在同一系统上,汇编语言同样是可重用的。

在这里使用汇编语言将会非常复杂。特别是一旦我需要支持微型SD卡、智能卡和ZigBee进行无线通信时,情况就更加复杂了。 :( - Piotr Czapla
6
简而言之,你可以花一年的时间用 C 写代码,也可以花三年的时间用汇编语言写代码。然后,当你开始一个使用不同处理器的新项目时,你可以花六个月用 C 添加新功能,或者花四年将其重写为汇编语言。 - Craig McQueen
如果你在四年后仍然使用同一个程序,那么很有可能你已经重写了大部分的代码。 - Toad

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接