Pio*_*pla 77 c c++ embedded c89
我的硬件C++和C89上有两个编译器
我正在考虑将C++与类一起使用但没有多态(以避免使用vtable).我想使用C++的主要原因是:
在开发非常有限的硬件(4kb RAM)时,您是否认为有理由坚持使用C89?
谢谢你的回答,他们真的很有帮助!
我认为这个主题通过,我会坚持使用C主要是因为:
因为你提供了很多好的答案,所以很难接受一个答案.不幸的是我不能创建一个wiki并接受它,所以我会选择一个让我最想的答案.
RBe*_*eig 64
对于资源非常有限的目标,例如4KB的RAM,我会在做出大量努力之前用一些样本测试水域,这些努力无法轻易移植回纯ANSI C实现.
嵌入式C++工作组确实提出了该语言的标准子集和标准库的标准子集.不幸的是,当C用户期刊去世时,我忘记了这种努力.它看起来像有在文章维基百科,以及该委员会仍然存在.
在嵌入式环境中,您必须小心内存分配.要强制执行该操作,您可能需要将全局operator new()及其朋友定义为无法链接的内容,以便您知道它未被使用.new另一方面,当明智地使用放置以及稳定,线程安全和延迟保证的分配方案时,放置可能是您的朋友.
内联函数不会造成太大问题,除非它们足够大以至于它们本来应该是真正的函数.当然,他们替换的宏也有同样的问题.
模板也可能不会导致问题,除非它们的实例化运行无法进行.对于您使用的任何模板,请审核生成的代码(链接映射可能有足够的线索),以确保只发生您打算使用的实例.
可能出现的另一个问题是与调试器的兼容性.对于其他可用的硬件调试器来说,对与原始源代码的交互提供非常有限的支持并不罕见.如果你有效地必须在程序集中进行调试,那么C++的有趣名称错误会给任务增加额外的混乱.
RTTI,动态强制转换,多重继承,重度多态和异常都会带来一些运行时成本.如果使用这些功能,其中一些功能会超过整个程序,其他功能只会增加需要它们的类的权重.了解差异,并在充分了解至少粗略的成本/收益分析的情况下明智地选择高级功能.
在小型嵌入式环境中,您可以直接链接到实时内核,也可以直接在硬件上运行.无论哪种方式,您都需要确保运行时启动代码正确处理C++特定的启动杂项.这可能就像确保使用正确的链接器选项一样简单,但由于通常可以直接控制源到上电复位入口点,因此您可能需要对其进行审核以确保它能够完成所有操作.例如,在我工作的ColdFire平台上,开发工具附带了CRT0.S模块,该模块具有C++初始化程序,但注释掉了.如果我直接从盒子中使用它,我会被全局对象神秘化,它们的构造函数从未运行过.
此外,在嵌入式环境中,通常需要在硬件设备可以使用之前对其进行初始化,如果没有操作系统且没有引导加载程序,那么您的代码就是这样做的.您需要记住,在 main()调用之前运行全局对象的构造函数,因此您需要修改本地CRT0.S(或其等效项)以在调用全局构造函数之前完成硬件初始化.显然,最重要的main()是为时已晚.
Ste*_*off 42
使用C over C++的两个原因:
此外,原始问题和一些评论提到了4 Kb的RAM.对于典型的嵌入式处理器,RAM的数量(大部分)与代码大小无关,因为代码存储并从闪存运行.
当然,代码存储空间的数量是需要考虑的因素,但随着新的,更大容量的处理器出现在市场上,它不像过去那样只是成本最敏感的项目.
关于使用C++子集与嵌入式系统一起使用:现在有一个MISRA C++标准,值得一看.
编辑:另请参阅这个问题,这引发了关于嵌入式系统的C vs C++的争论.
Har*_*lby 25
在进行嵌入式开发时,可以避免任何可能导致问题的C++语言功能(运行时多态性,RTTI等).有一个嵌入式C++开发人员社区(我记得在旧的C/C++用户期刊中使用C++阅读嵌入式开发人员的专栏),我无法想象如果选择那么糟糕,他们会非常直言不讳.
lea*_*der 20
关于C++性能的技术报告是这类事情的一个很好的指南.请注意,它有一个关于嵌入式编程问题的部分!
另外,++提到了嵌入式C++的答案.标准不是100%的我的口味,但在决定你可能会丢弃C++的哪些部分时,这是一个很好的参考.
在为小平台编程时,我们禁用异常和RTTI,避免虚拟继承,并密切关注我们所处的虚拟函数的数量.
但是你的朋友是链接器映射:经常检查它,你会很快发现代码源和静态内存膨胀.
之后,标准的动态内存使用注意事项适用:在您提到的限制环境中,您可能根本不想使用动态分配.有时您可以使用内存池来获取小动态分配,或者"基于帧"的分配,您可以预先分配块并在以后丢弃整个块.
ark*_*rke 16
我建议使用C++编译器,但限制使用C++特定功能.您可以在C++中编写类似C的编程(在执行C++时包含C运行时,但在大多数嵌入式应用程序中,您仍然不使用标准库).
你可以继续使用C++类等
小智 14
作为固件/嵌入式系统工程师,我可以告诉大家一些原因,为什么C仍然是C++的第一选择,是的,我能熟练掌握它们.
1)我们开发的一些目标有64kB的RAM代码和数据,所以你必须确保每个字节数,是的,我已经处理代码优化,以节省4个字节,花了我2个小时,这是在2008年.
2)在我们让它们进入最终代码之前,每个C库函数都会被检查,因为大小限制,所以我们更喜欢人们不使用除法(没有硬件分隔符,所以需要一个大的库),malloc(因为我们没有堆) ,所有内存都是从512字节块中的数据缓冲区分配的,并且必须经过代码审查),或其他面向对象的实践,会带来很大的损失.请记住,您使用的每个库函数都计算在内.
3)有没有听说过覆盖这个词?你有这么少的代码空间,有时你必须用另一组代码交换东西.如果调用库函数,则库函数必须是常驻函数.如果只在覆盖函数中使用它,那么依赖于太多面向对象的方法会浪费大量空间.所以,不要假设任何C库函数,更不用说接受C++了.
4)由于有限的硬件设计(即以某种方式连接的ECC引擎)或应对硬件错误,需要进行铸造和均匀打包(其中未对齐的数据结构跨越字边界).你不能明确地假设太多,那么为什么反对它太过分?
5)最坏的情况:消除一些面向对象的方法会迫使开发在使用可能爆炸的资源之前进行思考(即在堆栈上而不是从数据缓冲区分配512字节),并防止一些潜在的最坏情况没有测试或消除整个代码路径.
6)我们使用大量抽象来保持硬件不受软件影响,并使代码尽可能便携,并且模拟友好.硬件访问必须包装在有条件地在不同平台之间编译的宏或内联函数中,数据类型必须作为字节大小而不是目标特定,不允许直接指针使用(因为某些平台假设内存映射I/O是与数据存储器相同)等
我能想到更多,但你明白了.我们固件人员确实有面向对象的培训,但嵌入式系统的任务可以是硬件导向的,低级别的,它本质上不是高级别或可抽象的.
顺便说一下,我一直在使用的每个固件工作都使用源代码控制,我不知道你从哪里得到这个想法.
来自SanDisk的一些固件人.
Roc*_*net 10
我个人的偏好是C,因为:
- 我知道每行代码的作用(和成本)
- 我不太清楚C++知道每行代码的作用(和成本)
人们为什么这么说?你不知道什么C的每一行正在做,除非你检查ASM输出.C++也是如此.
例如,asm这个无辜的陈述产生了什么:
a[i] = b[j] * c[k];
Run Code Online (Sandbox Code Playgroud)
它看起来相当无辜,但是基于gcc的编译器会为8位微处理器生成这个asm
CLRF 0x1f, ACCESS
RLCF 0xfdb, W, ACCESS
ANDLW 0xfe
RLCF 0x1f, F, ACCESS
MOVWF 0x1e, ACCESS
MOVLW 0xf9
MOVF 0xfdb, W, ACCESS
ADDWF 0x1e, W, ACCESS
MOVWF 0xfe9, ACCESS
MOVLW 0xfa
MOVF 0xfdb, W, ACCESS
ADDWFC 0x1f, W, ACCESS
MOVWF 0xfea, ACCESS
MOVFF 0xfee, 0x1c
NOP
MOVFF 0xfef, 0x1d
NOP
MOVLW 0x1
CLRF 0x1b, ACCESS
RLCF 0xfdb, W, ACCESS
ANDLW 0xfe
RLCF 0x1b, F, ACCESS
MOVWF 0x1a, ACCESS
MOVLW 0xfb
MOVF 0xfdb, W, ACCESS
ADDWF 0x1a, W, ACCESS
MOVWF 0xfe9, ACCESS
MOVLW 0xfc
MOVF 0xfdb, W, ACCESS
ADDWFC 0x1b, W, ACCESS
MOVWF 0xfea, ACCESS
MOVFF 0xfee, 0x18
NOP
MOVFF 0xfef, 0x19
NOP
MOVFF 0x18, 0x8
NOP
MOVFF 0x19, 0x9
NOP
MOVFF 0x1c, 0xd
NOP
MOVFF 0x1d, 0xe
NOP
CALL 0x2142, 0
NOP
MOVFF 0x6, 0x16
NOP
MOVFF 0x7, 0x17
NOP
CLRF 0x15, ACCESS
RLCF 0xfdf, W, ACCESS
ANDLW 0xfe
RLCF 0x15, F, ACCESS
MOVWF 0x14, ACCESS
MOVLW 0xfd
MOVF 0xfdb, W, ACCESS
ADDWF 0x14, W, ACCESS
MOVWF 0xfe9, ACCESS
MOVLW 0xfe
MOVF 0xfdb, W, ACCESS
ADDWFC 0x15, W, ACCESS
MOVWF 0xfea, ACCESS
MOVFF 0x16, 0xfee
NOP
MOVFF 0x17, 0xfed
NOP
Run Code Online (Sandbox Code Playgroud)
产生的指令数量主要取决于:
在微小的嵌入式世界中尤其如此,其中处理器只是没有设置来处理C.所以我的答案是C和C++彼此一样糟糕,除非你总是检查asm输出,在这种情况下他们和他们一样好.
雨果
我听说有些人喜欢C用于嵌入式工作,因为它更简单,因此更容易预测将生成的实际代码.
我个人认为编写C风格的C++(使用类型安全模板)会给你带来很多好处,但我看不出任何真正的理由.
我认为没有理由使用C而不是C++.无论你在C中做什么,你也可以用C++做.如果要避免VMT的开销,请不要使用虚方法和多态.
但是,C++可以提供一些非常有用的习惯用语,而且没有开销.我最喜欢的一个是RAII.在内存或性能方面,类不是必需的昂贵......
我在IAR Workbench上为ARM7嵌入式paltform编写了一些代码.我强烈建议依靠模板进行编译时优化和路径预测.避免像瘟疫一样动态铸造.根据Andrei Alexandrescu的书" Modern C++ design"中的规定,使用特征/策略.
我知道,这可能很难学,但我也确信您的产品将从这种方法中受益.
小智 6
人类的思维通过尽可能多的评估来处理复杂性,然后决定关注什么是重要的,并丢弃或贬低其余的。这是营销品牌背后的全部基础,主要是图标。
为了对抗这种倾向,我更喜欢 C 而不是 C++,因为它迫使你思考你的代码,以及它如何与硬件更密切地交互——无情地接近。
从长期的经验来看,我相信 C 迫使你想出更好的问题解决方案,部分是通过让你的方式而不是强迫你浪费大量时间来满足一些编译器作者认为是个好主意的约束,或者弄清楚“幕后”发生了什么。
在这种情况下,像 C 这样的低级语言让你花很多时间专注于硬件和构建良好的数据结构/算法包,而高级语言让你花很多时间挠头想知道那里发生了什么,以及为什么你不能在你的特定上下文和环境中做一些完全合理的事情。击败你的编译器提交(强类型是最坏的冒犯者)不是对时间的有效利用。
我可能很适合程序员模式 - 我喜欢控制。在我看来,这不是程序员的性格缺陷。控制是我们得到报酬做的事情。更具体地说,完美控制。C 为您提供了比 C++ 多得多的控制权。
一个很好的理由,有时唯一的原因是特定的嵌入式系统仍然没有C++编译器.例如,对于Microchip PIC微控制器就是这种情况.它们非常容易编写,并且它们有一个免费的C编译器(实际上是C的一个轻微变体)但是看不到C++编译器.
对于一个限制为4K的ram的系统,我会使用C而不是C++,这样你就可以确保看到正在发生的一切.使用C++的事情是,使用更多的资源(包括CPU和内存)比看起来像浏览代码一样容易.(哦,我只是创建另一个BlerfObject来做那个......哎呀!内存不足!)
您可以在C++中完成,如前所述(没有RTTI,没有vtable等等),但是您将花费尽可能多的时间来确保您的C++使用不会像您在C中的等效操作那样远离您.
就我个人而言,对于 4kb 内存,我认为您不会从 C++ 中获得更多收益,因此只需选择一个似乎最适合该工作的编译器/运行时组合,因为语言可能并不那么重要。
请注意,无论如何,这也不仅仅与语言有关,因为图书馆也很重要。通常,C 库的最小大小会稍小一些,但我可以想象,针对嵌入式开发的 C++ 库会被缩减,因此请务必进行测试。