许多嵌入式工程师使用c ++,但有些人认为它很糟糕,因为它是“面向对象的”?
面向对象是否真的对嵌入式系统有害,如果是这样,为什么会出现这种情况呢?
编辑:这是一个快速参考,询问:
所以我们 更喜欢人们不要使用除...,malloc ......或其他对象 携带大的定向练习 罚。
我想问题是嵌入式系统环境中被认为是重量级的对象?这里的一些答案表明他们是,有些人认为他们不是。
答案 0 :(得分:13)
从表面上看,动态内存分配与面向对象的软件设计是完全独立的概念,因此它是完全错误的。您可以使用面向对象的设计,而不是使用动态内存分配。
实际上,你可以在一定程度上在C中执行OO(这就是Linux内核所做的)。许多嵌入式开发人员不喜欢C ++的真正的原因是它非常复杂,很难在其中编写直接且可预测的代码。 Linus a good recent rant解释了为什么他不喜欢C ++(我承诺,它比他的old one更好,更合理)。可能大多数人都没有很清楚地表达出来。
答案 1 :(得分:13)
虽然我不确定它是否回答了您的问题,但我可以总结一下我以前的公司源代码是纯C的原因。
首先值得总结一下情况:
鉴于此,我们完全使用C语言,甚至只使用了一组受限制的C 89.结果代码非常便于携带。我们经常使用面向对象的概念。
这些天“嵌入式”是一个非常广泛的定义。它涵盖了从没有RAM或C编译器的8位微处理器到基本上高端PC(尽管没有运行Microsoft Windows)的所有内容 - 我不知道您的项目/公司在该范围内的位置。
答案 2 :(得分:6)
是什么让你说C ++是面向对象的? C ++是多范式的,并非由于其开销,C ++提供的所有功能对嵌入式市场都很有用。 (所以......只是不要使用这些功能!问题解决了!)
答案 3 :(得分:4)
“面向对象”的任何内容都不利于嵌入式系统。 OO只是一种思考软件的方式。
对于嵌入式系统来说,最糟糕的是,他们通常会使用不太复杂的调试器,而C ++会在你背后做很多疯狂的事情,可以这么说。那些难以访问的代码将让你疯狂。
答案 4 :(得分:4)
面向对象非常适合嵌入式系统。它主要关注封装,数据隐藏和代码共享。可以使用面向对象的嵌入式系统,而无需划分或动态内存分配。
分区和动态内存分配是嵌入式系统的敌人,无论面向对象,面向数据还是程序编程。这些概念可能会也可能不会用于面向对象设计的实现。
面向对象允许UART类在不知道Message对象内容的情况下传输Message对象的实例。 Message可以是基类,有几个后代类。
C ++语言通过允许构造函数,复制构造函数和析构函数来帮助促进嵌入式系统中的安全编码,这些编译器只能在最高纪律的C语言嵌入式系统中记住。
异常处理也是使用C语言工作的一种痛苦。 C ++提供了嵌入到语言中的更好的工具。
C ++语言提供了用于编写公共代码以处理不同数据类型的模板。典型的例子是环形缓冲区或循环队列。在C语言中,必须使用“指向void的指针”,以便可以传递任何对象。 C ++提供了一个模板,因此可以编写一个使用不同数据类型的Circular_Queue类,并具有更好的编译时类型检查。
继承允许更好的代码共享。共享代码被考虑到基类中,并且可以创建共享相同功能的子类;通过继承。
C语言提供函数指针。 C ++语言为函数对象(具有属性的函数指针)提供了工具。
抱歉,我不喜欢那些将嵌入式系统限制为C语言的人因为谣言和对C ++的知识和经验不足。
答案 5 :(得分:3)
面向对象的设计本身并不错。答案在于你的引用。特别是在实时嵌入式系统中,您希望尽可能轻松高效地编写代码。引用中提到的内容(对象,除法,动态内存分配)相对较重,通常可以用更简单的替代方法替换(例如,使用位操作来近似除法,在堆栈上分配内存或使用静态池)来改进在时间关键系统中的表现。
答案 6 :(得分:2)
C ++的设计理念是不支付你不使用的东西。因此,除了缺乏良好的嵌入式编译器之外,没有真正的理由。
也许CFront可以将C ++编译成C,其中已经无数的编译器......
编辑:Comeau编译器将C ++转换为普通C,因此no-compiler参数不成立。
答案 7 :(得分:2)
正如其他人所说,'嵌入式'涵盖了广泛而多样的硬件/软件选项。但...
您给出的报价将给微控制器嵌入式类型带来颤抖。动态分配是禁忌,如果您有错误,则会以不可预测的方式使系统崩溃。由于他们在执行时间永远,因此非常不鼓励分歧。只是因为它们倾向于随身携带许多“东西”,所有这些“东西”占用空间,微控制器没有任何物体,因此不鼓励使用物体。
我认为嵌入式是一个小而具体的项目,您不必担心可扩展性或可移植性。您可以使用C语言编写干净的代码,这些代码仅可以完美地执行您希望设备执行的操作。您选择一个芯片系列,这样您就可以在不同的硬件选项中移动(几乎相同)相同的代码,只需对您的写入端口进行微调或初始化配置保险丝。
因此,您无需定义
因为你只是在丰田公司工作。并且凯美瑞和卡罗拉之间的加速度差异作为常数存储在寄存器中。
答案 8 :(得分:1)
编程始终是为工作使用正确的工具。没有轻拍的答案,在嵌入式世界尤其如此。如果你想要熟练掌握嵌入式开发,你就会像C语言一样熟悉C语言。
答案 9 :(得分:1)
如上所述,它背后的面向对象/ malloc / math会带来什么损失 - 代码大小和CPU周期都是嵌入式的。
作为一个例子,在循环中包含sqrt()函数在递归计算中增加了很多开销,我们不得不将其删除并对其进行快速近似,如果我没记错的话,使用查找表。
一定要使用您喜欢的任何工具/语言,但您至少需要抬起盖子并检查背后产生多少额外代码。
答案 10 :(得分:-1)
首先,让我们将其分开:
因此我们更希望人们不要使用除法...,malloc ...或其他会带来巨大损失的面向对象的实践。
除法和malloc
并不是面向对象编程所独有的,它们也存在于过程语言中(并且可能是功能性的,以及您可能想到的任何其他范式)。
在嵌入式系统上,如果分区和malloc
的资源足够有限,那么这可能是一个问题,这是事实,但是无论您使用哪种编程范例,它们都将成为问题。
主要问题“面向对象对嵌入式系统不利吗?”。
首先,“面向对象”的范围很广。对于实际含义,有些人有相互矛盾的想法。有一个极简主义的定义,其中对象本质上只是函数(或“方法”)和数据的捆绑,还有一个更“纯粹”的定义,其中还包括继承和多态性等功能。
如果采用OOP的最低限度定义,则否-OOP对于嵌入式系统来说还不错。它确实取决于语言,但是使用对象和不使用对象一样便宜(在某些情况下可能更便宜)是完全可能的。在C ++中,一个对象(没有virtual
方法,我将在稍后介绍)占用的内存不会超过其各个字段(如果它们不是对象的一部分)所占用的内存。在C ++中,对象的(大小)等于其部分的(大小)之和。
但是,如果您采用OOP的“清教徒”观点,并坚持包括继承和多态性,那么答案是“是的,这很不好”。继承可能不那么在乎(取决于语言),但是通过virtual
方法进行的多态性无疑是一种内存消耗。 virtual
函数通常通过维护一个“ vtable”(虚拟方法表)来实现,该表存储指向正确函数的指针,每个对象必须存储一个指向其vtable的指针以启用动态调度(调用虚拟函数的过程) )正常工作。在某些情况下,与不需要继承的解决方案相比,继承可以使用更多的内存-通常,在将继承与组合进行比较时,组合有时会使用较少的内存。
最后一点,特别是对于C ++而言(因为这是人们谈论嵌入式系统上使用OOP时通常的意思)。人们经常说“ C ++在背后做一些奇怪的事情” –它在做某些事情时在查看代码时不会立即使这些事情变得显而易见,例如生成我前面提到的vtable,但是它并没有做这些事情您的背部”以阻止您这样做,是因为这些只是实现所使用功能的必要条件。总体而言,“幕后”几乎没有有害的事情发生,并且它所做的事情并非完全是神秘的或神秘的,它们通常是众所周知的,并且是程序员进行编程时应注意的事情嵌入式系统。如果您对它们一无所知,那么您就不会正确地了解自己的工具,应该对它们进行更多研究。
说了这么多,请记住,人们可以自由选择使用或不使用哪些语言功能。避免使用诸如虚拟函数之类的更昂贵的功能是绝对有意义的,但是仅仅因为它具有一些昂贵的完全可选功能(例如virtual功能)-那只是把婴儿扔出去的洗澡水。