是否有任何理由使用C而不是C ++进行嵌入式开发?


81

我的硬件C ++和C89上有两个编译器

我正在考虑将C ++与类一起使用,但不要使用多态性(以避免使用vtables)。我想使用C ++的主要原因是:

  • 我更喜欢使用“内联”函数而不是宏定义。
  • 我想使用名称空间作为前缀,使代码混乱。
  • 我认为C ++的类型更安全,主要是因为模板和冗长的强制转换。
  • 我真的很喜欢重载的函数和构造函数(用于自动转换)。

在为非常有限的硬件(4kb RAM)开发时,您是否看到任何理由坚持使用C89?

结论

感谢您的回答,它们确实很有帮助!

我考虑了这个问题,因此我坚持使用C,主要是因为:

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

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


11
一件事:始终清楚要用哪种语言编写。不要尝试用“ C / C ++”编写程序。用C编写,或者用C ++编写,知道将使用哪些语言功能,哪些不会使用。
David Thornley,2009年


定义“嵌入式开发”
Marco van de Voort 2010年

@DavidThornley,您也许非常适合嵌入式案例,但是我感到非常惊喜的是,C和C ++混合代码完美地结合在一起,我希望通过STL扩展像Kamailio这样的通用行业开源应用程序。我正式鼓励使用STL和C代码,因为它提供了强大的功能和易于维护的功能,同时又产生了几乎为零的问题(C ++中缺少嵌入式结构是对C ++的可怕罪行,应尽快予以纠正。 )。
user2548100 2014年

值得深思的是,这是一篇很棒的文章,ZeroMQ的设计者和作家讨论了为什么他后悔用C ++而不是C编写代码库的原因。这根本不是我所期望的,并且出于此页其他地方找不到的原因。250bpm.com/blog:4
user2548100 2014年

Answers:


47

在C ++上使用C的两个原因:

  1. 对于许多嵌入式处理器,要么没有C ++编译器,要么您必须为此付出额外的钱。
  2. 我的经验是,很大一部分嵌入式软件工程师很少或没有C ++的经验-要么是由于(1)的原因,要么是因为它倾向于不接受电子工程学学位的授课,所以最好坚持一下他们知道什么。

此外,原始问题和许多评论都提到了4 Kb的RAM。对于典型的嵌入式处理器,RAM的数量(大部分)与代码大小无关,因为代码存储在闪存中并从中运行。

当然,要记住一定数量的代码存储空间,但是随着新的,功能更强大的处理器出现在市场上,它比以前的问题更加重要,但对成本最敏感的项目除外。

关于将C ++子集用于嵌入式系统的问题:现在有一个MISRA C ++标准,可能值得一看。

编辑:另请参阅此问题,这引发了有关嵌入式系统C和C ++的争论。


2
请参阅下面的较长答复:C ++往往使将常量数据放入FLASH变得非常困难。
jakobengblom2

3
使用C而不是C ++的潜在好理由是C的标准ABI。只是为了完整性。
克里斯·卢茨

66

对于资源非常有限的目标(例如4KB RAM),我将先进行一些示例测试,然后再进行大量无法轻松移植回纯ANSI C实现的工作。

嵌入式C ++工作组确实提出了该语言的标准子集和标准库的标准子集。不幸的是,当《 C User's Journal》死后,我忘记了那种努力。看来Wikipedia上有一篇文章,并且该委员会仍然存在。

在嵌入式环境中,您确实必须注意内存分配。要执行这种护理,您可能需要将全局变量operator new()及其朋友定义为甚至无法链接的对象,以使您知道未使用它。放置new具有稳定,线程安全的,并且延迟保证分配方案沿其谨慎使用时,另一方面很可能是你的朋友。

内联函数不会造成太大问题,除非它们足够大以至于它们本来应该是真正的函数。当然,它们替换的宏也有同样的问题。

模板也不会导致问题,除非其实例化运行正常。对于您使用的任何模板,请审核生成的代码(链接映射可能具有足够的线索),以确保仅发生了您打算使用的实例。

可能出现的另一个问题是与调试器的兼容性。对于其他可用的硬件调试器来说,与原始源代码交互的支持非常有限。如果您必须有效地在汇编中进行调试,那么有趣的C ++名称处理可能会使任务更加混乱。

RTTI,动态强制转换,多重继承,繁重的多态性和异常都会为使用它们带来一些运行时成本。如果使用了其中一些功能,则这些功能在整个程序中的成本会很高,而其他功能只会增加需要它们的类的权重。了解差异,并充分了解至少粗略的成本/收益分析,明智地选择高级功能。

在小型嵌入式环境中,您要么直接链接到实时内核,要么直接在硬件上运行。无论哪种方式,您都需要确保您的运行时启动代码可以正确处理C ++特定的启动杂项。这可能就像确保使用正确的链接器选项一样简单,但是由于直接控制源到上电复位入口点是很常见的,因此您可能需要审核一下以确保它可以执行所有操作。例如,在我工作的ColdFire平台上,CRT0.S模块附带的开发工具具有C ++初始化程序,但已注释掉。如果我直接使用它,那我将对那些从未构造过构造函数的全局对象感到困惑。

另外,在嵌入式环境中,通常需要先初始化硬件设备,然后才能使用它们,如果没有操作系统,也没有引导加载程序,则代码是由您执行的。您将需要记住,全局对象的构造函数是 main()调用之前运行的因此您需要修改本地CRT0.S(或其等效对象),以便调用全局构造函数本身之前完成硬件初始化。显然,顶部main()已经太晚了。


1
这需要我无法提供的更多支持!伟大的答案。
哈珀·谢尔比

+1,好答案。但是我认为,您真正需要担心的唯一模板实例化是(相对较少)的递归类型-对于“常规”非递归类型,实例化等于您无论如何都要手动键入的代码。
j_random_hacker

2
@j_random_hacker,是的。但是,当第二个(或第三个)实例化出现在使用时适当的类型强制可能阻止了该实例化时,模板的习惯可能会导致偶尔的意外。这只是需要注意的事情。
RBerteig

@RBerteig:好的一点,模板允许更少的类型强制可能性=>与非模板代码相比,生成的实例化可能更多。
j_random_hacker,2009年

26

不能。在进行嵌入式开发时,可以避免使用任何可能引起问题的C ++语言功能(运行时多态性,RTTI等)。有一个嵌入式C ++开发人员社区(我记得在旧的《 C / C ++用户杂志》中读过使用C ++的嵌入式开发人员的专栏文章),而且我无法想象如果选择那么糟糕,他们会非常直言不讳。


20

C ++性能技术报告》是此类事情的绝佳指南。请注意,其中有一节涉及嵌入式编程问题!

另外,++在答案中提到了嵌入式C ++。该标准并不是100%符合我的喜好,但是在确定您可能放弃的C ++部分时,它是一个很好的参考。

在小型平台上编程时,我们禁用异常和RTTI,避免虚拟继承,并密切关注我们周围存在的虚拟功能的数量。

不过,您的朋友就是链接器映射:经常检查它,您将迅速发现代码源和静态内存膨胀。

之后,应用标准的动态内存使用注意事项:在您提到的那种受限的环境中,您可能根本不希望使用动态分配。有时,您可以放弃用于小型动态分配或“基于帧”分配的内存池,您可以在其中预先分配一个块,然后将整个对象扔掉。


16

我建议使用C ++编译器,但要限制使用C ++特定功能。您可以在C ++中像C一样进行编程(使用C ++时包含C运行时,尽管在大多数嵌入式应用程序中,您始终不使用标准库)。

您可以继续使用C ++类等。

  • 限制对虚函数的使用(正如您所说的)
  • 限制模板的使用
  • 对于嵌入式平台,您需要覆盖new运算符和/或将new放置用于内存分配。

8
当然,如果您已经基本在编写C,则最好将其正式化。
查克(Chuck)

6
为什么限制使用模板?我认为模板功能在嵌入式系统中可能非常有用,例如展开循环。
Piotr Czapla

1
您仍然可以使用模板,但是我会非常小心,因为它们会迅速增加输出二进制文件的大小。当然,如果您的代码直接从ROM或类似文件中运行,并且您有剩余的ROM空间,那么可以肯定,但是除此之外,您还需要注意对模板的操作(每个模板实例基本上都是所有重复的模板化代码)在最坏的情况下在最终可执行文件中)。
09年

14

作为固件/嵌入式系统工程师,我可以告诉大家C为什么仍然是C ++排名第一的原因,是的,我精通这两个方面。

1)我们开发的某些目标针对代码和数据都具有64kB的RAM,因此您必须确保每个字节计数,是的,我已经进行了代码优化以节省4个字节,这使我花费了2个小时, 2008。

2)每个C库函数都会在进入最终代码之前进行审查,由于大小限制,因此我们希望人们不要使用除法(没有硬件除法器,因此需要一个大库),malloc(因为我们没有堆) ,则所有内存均以512字节块的形式从数据缓冲区中分配,并且必须进行代码审查),或其他会带来较大损失的面向对象的实践。请记住,您使用的每个库函数都很重要。

3)听说过术语叠加吗?您的代码空间非常小,有时您不得不将其与另一组代码交换出去。如果调用库函数,则该库函数必须驻留。如果仅在覆盖函数中使用它,那么您将浪费大量空间,这取决于太多的面向对象的方法。因此,不要假设任何C库函数,更不用说C ++了。

4)由于有限的硬件设计(例如,以某种方式连接的ECC引擎)或应付硬件错误,因此需要强制转换甚至打包(其中未对齐的数据结构跨越字边界)。您不能过分地暗自假设,那么为什么要过多地定向对象呢?

5)最坏的情况:消除一些面向对象的方法将迫使开发人员在使用可能爆炸的资源之前进行思考(即在堆栈上分配512字节而不是从数据缓冲区分配),并防止某些可能的最坏情况发生不能一起测试或消除整个代码路径。

6)我们确实使用了大量抽象来使硬件与软件保持隔离,并使代码尽可能可移植,并且对仿真友好。硬件访问必须包装在宏或内联函数中,这些宏或内联函数有条件地在不同平台之间编译,数据类型必须强制转换为字节大小而不是特定于目标,强制使用指针(因为某些平台假定内存映射的I / O是与数据存储器相同),等等。

我可以想到更多,但是您明白了。我们的固件人员确实接受过面向对象的培训,但是嵌入式系统的任务可能是面向硬件的并且是低级的,以至于它不是高级的,或者本质上不是抽象的。

顺便说一句,我从事的每个固件工作都使用源代码控制,我不知道您从何处得到这个想法。

-SanDisk的一些固件专家。


早在90年代初,覆盖是一种非常流行的技术(至少在DOS世界中如此)
psihodelia 2012年

好点成。C ++在功能有限且资源更加有限的项目中就像电话亭中的Sumo摔角手一样。

4
我相信这个答案是非常主观的,没有提供具体的推理。
Venemo

1
C ++不一定意味着“面向对象”。
马丁·邦纳

1
嵌入式系统的任务本质上是不可抽象的,这是不正确的。您在第6点中自己说过:“我们确实使用了很多抽象来防止来自sw的硬件并使代码尽可能地可移植” :-) BTW:“抽象”并不一定意味着“多态”。
Daniele Pallastrelli,

9

我的个人偏好是C,因为:

  • 我知道每一行代码在做什么(和花费多少)
  • 我对C ++不太了解,无法知道每一行代码在做什么(和花费多少)

人们为什么这么说?你知道什么C的每一行正在做,除非你检查ASM输出。C ++也是如此。

例如,此无辜的声明会产生什么asm:

a[i] = b[j] * c[k];

看起来很纯真,但是基于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

产生的指令数量很大程度上取决于:

  • a,b和c的大小。
  • 这些指针是存储在堆栈上还是全局的
  • i,j和k是在堆栈上还是全局

在微小的嵌入式世界中尤其如此,在该世界中,处理器没有设置为可以处理C。因此,我的回答是C和C ++彼此一样坏,除非您始终检查asm输出,在这种情况下,它们彼此一样好。

雨果


2
还要注意,在所有实际调用乘法函数的指令中间都有一个调用指令。所有这些代码甚至都不是乘法指令!
Rocketmagnet

熟悉micro的人通常会知道一种简单的方法来单独处理C代码的每个部分,并且像样的编译器不应产生比这更糟糕的代码。可以有效处理上述表达式的唯一方法是,如果做出的假设可能不适合C编译器。
超级猫

8

我听说有些人更喜欢C进行嵌入式工作,因为它更简单,因此更容易预测将要生成的实际代码。

我个人认为编写C风格的C ++(使用类型安全的模板)将为您带来很多好处,但我看不出没有这样做的任何真正原因。


+1,透明性始终很重要,对于带有(可能是)受约束的调试工具的受约束的环境,透明度可能更重要。
j_random_hacker

7

我认为没有理由使用C而不是C ++。无论您在C中能做什么,都可以在C ++中做到。如果要避免VMT的开销,请不要使用虚拟方法和多态性。

但是,C ++可以提供一些非常有用的惯用法,而不会产生开销。我最喜欢的之一是RAII。就内存或性能而言,类不一定是昂贵的。


6

我已经在IAR Workbench上为ARM7嵌入式paltform编写了一些代码。我强烈建议依赖模板进行编译时优化和路径预测。避免像瘟疫一样动态投掷。按照Andrei Alexandrescu的《Modern C ++ design》一书中的规定,使用特征/策略来发挥自己的优势。

我知道这可能很难学习,但我也确信您的产品将从这种方法中受益。


5

一个很好的理由,有时甚至是唯一的原因,是特定的嵌入式系统仍然没有C ++编译器。例如,对于Microchip PIC单片机就是这种情况。它们非常易于编写,并且具有免费的C编译器(实际上是C的微小变体),但是看不到C ++编译器。


1
科莫计算(comeaucomputing.com)出售C ++编译器,其编译为C.
托马斯大号Holaday

3
真是的 那个网站想吐。
shoosh

@shoosh:是的,网站设计很糟糕。但是,至少在标准一致性方面,编译器本身被认为是该领域的领导者(我没有有关性能的信息)。
j_random_hacker

该网站使我感到自己被困在一个生活,呼吸和非常生气的水果沙拉中。
蒂姆·波斯特

5

对于限于ram 4K的系统,我将使用C而不是C ++,只是为了确保可以看到所有发生的事情。C ++的问题在于,使用它比看一眼代码要容易得多,而要使用更多的资源(CPU和内存)。(哦,我将创建另一个BlerfObject来执行此操作……糟糕!内存不足!)

如前所述,您可以在C ++中做到这一点(没有RTTI,没有vtables等),但是您将花费大量的时间来确保您的C ++使用不会像在C语言中所做的那样远离您。


2
您的最后一句话是正确的,但无关紧要,因为C ++提供了优于C的其他优势(可能),从而达到了平衡。Piotr已经提到了其中一些(零成本)优势。
Konrad Rudolph

5

人类的思维方式是通过尽可能多地评估,然后确定要重点关注的内容,然后舍弃或贬值其余部分,来处理复杂性。这是行销品牌(主要是图示)背后的全部基础。

为了克服这种趋势,我更喜欢C而不是C ++,因为它迫使您考虑代码,以及代码如何与硬件更紧密地交互-不断地紧密协作。

从长期的经验来看,我相信C会迫使您提出更好的问题解决方案,部分原因是您摆脱了束手无策,而不是强迫您浪费大量时间来满足约束,一些编译器作者认为这是一个好主意,或弄清楚“幕后”的情况。

因此,像C这样的低级语言使您花费大量时间专注于硬件和构建良好的数据结构/算法包,而高级语言使您花费了大量时间来思考其中发生了什么,以及为什么您不能在特定的上下文和环境中做一些完全合理的事情。击败编译器进行提交(强类型输入是最严重的违法者)并不是对时间的有效利用。

我可能很适合程序员的工作方式-我喜欢控制。在我看来,这不是程序员的人格缺陷。控制是我们得到报酬要做的事情。更具体地说,轻松控制。与C ++相比,C给您更多的控制权。


ZeroMQ的作者Martin Sistrik在讨论他为什么现在希望用C而不是C ++编写ZeroMQ的论述中几乎持同一观点。检出250bpm.com/blog:8
user2548100 2014年

3

就个人而言,只有4kb的内存,我想说的是C ++并不会给您带来更多的好处,因此,选择一种看似最适合该工作的编译器/运行时组合的语言,因为语言可能无关紧要。

注意,无论如何,语言也不是全部,因为库也很重要。通常,C库的最小大小会稍小一些,但是我可以想象针对嵌入式开发的C ++库会减少,因此一定要进行测试。


2

C在可移植性上取胜-因为它在语言规范方面不那么模棱两可;因此在不同的编译器之间提供了更好的可移植性和灵活性(减轻了麻烦)。

如果您不打算利用C ++功能来满足需要,那么请使用C。


无论是语言是毫不含糊的,取决于是否有一个把它作为指定事以前认为的常识,但现在都没有[例如,对于32位无声环绕二进制补码的硬件编译器应该处理类似unsigned mul(unsigned short x, unsigned short y) { return x*y;}为无副作用,即使乘积超过2147483647,或应void get_float_bits(float *fp, uint32_t n) { *(uint32_t)fp = n; }视为可能会改变a float]的值。
超级猫

2

在为非常有限的硬件(4kb RAM)开发时,您是否看到任何理由坚持使用C89?

就嵌入式应用程序而言,就个人而言(当我说嵌入式程序时,我并不是说winCE,iPhone等。今天的嵌入式设备肿了)。我的意思是资源有限的设备。我更喜欢C,尽管我也使用C ++。

例如,您正在谈论的设备具有4kb的RAM,正因为如此,我才不考虑使用C ++。当然,您可以使用C ++设计一些较小的东西,并像其他文章所建议的那样限制您在应用程序中的使用,但是C ++“可能”最终可能会使您的应用程序复杂化/膨胀。

您要静态链接吗?您可能想比较使用c ++和c的静态虚拟应用程序。这可能会导致您考虑使用C。另一方面,如果您能够在内存需求内构建C ++应用程序,那就去吧。

恕我直言,总的来说,我喜欢在嵌入式应用程序中了解所有发生的事情。谁在使用内存/系统资源,多少?为什么?他们什么时候释放他们?

在为具有X数量的资源,CPU,内存等资源的目标进行开发时。我尽量避免使用那些资源,因为您永远不知道将来会发生什么需求,因此您需要向项目中添加更多代码,被“假定”为一个简单的小型应用程序,但最终变得更大。


1
我一定会比较两个编译器。(顺便说一句,由于没有操作系统,我无法动态链接)
Piotr Czapla

2

我的选择通常取决于我们决定使用的C库,该库是根据设备需要执行的操作选择的。因此,9/10次..最终是uclibc或newlib和C。我们使用的内核对此也有很大影响,或者如果我们正在编写自己的内核。

这也是共同点的选择。大多数优秀的C程序员在使用C ++时都没有问题(尽管许多人抱怨他们在使用C ++的整个过程中)..但是,根据我的经验,我还没有发现相反的说法是正确的。

在我们正在研究的项目中(涉及基础内核),大多数事情都是用C完成的,但是在C ++中实现了一个小的网络堆栈,因为使用C ++进行网络连接更容易且问题更少。

最终结果是,该设备可以运行并通过验收测试,否则将无法通过。如果您可以使用语言z在xx堆栈中实现foo并在yy堆约束中实现,请继续使用它,使用可以提高生产率的任何方法。

我的个人偏好是C,因为:

  • 我知道每一行代码在做什么(和花费多少)
  • 我对C ++不太了解,无法知道每一行代码在做什么(和花费多少)

是的,我对C ++感到满意,但是我对它的了解不如标准C。

现在,如果您可以说相反的话,那么,请使用您所知道的:)如果它有效,通过测试等,这是什么问题?


2
>#我知道每一行代码在做什么(和花费多少)编写了编译器后,我不能确定...一个好的C编译器可以对您的代码做令人惊讶的事情,因为它对以下方面有很好的了解东西。它不会逐行编译。
jakobengblom2

@ jakobengblom2:对于嵌入式开发,拥有一致的性能通常比拥有最高的性能更为重要。如果要确定一段代码是否满足时序要求,那么让编译器采用可在实际固件中无法使用的“测试”固件中使用的优化措施,就没有什么用。
超级猫

2

您有多少ROM /闪存?

4kB的RAM仍然意味着有数百KB的FLASH可以存储实际的代码和静态数据。这种大小的RAM往往只用于变量,如果您小心使用这些变量,就可以将相当大的程序装入内存中的代码行。

但是,由于对象的运行时构造规则,C ++倾向于使将代码和数据放入FLASH更加困难。在C语言中,可以轻松地将常量结构放入FLASH存储器中,并作为硬件常量对象进行访问。在C ++中,一个常量对象将要求编译器在编译时评估构造函数,我认为这仍然超出了C ++编译器的能力(从理论上讲,您可以做到,但是在实践中很难做到) 。

因此,在“小型RAM”,“大型FLASH”这类环境中,我每天都会使用C。请注意,i C99是一个不错的中间选择,它具有大多数非基于类的代码的C ++功能。


3
是否有任何理由为什么将相同的结构放入C中的Flash存储器中,而最终也不会出现在C ++中的Flash中?你不会一个构造函数添加到C ++的结构。
jalf

1

一般没有 C ++是C的超集。对于新项目来说尤其如此。

您在避免C ++构造方面走上了正确的路,这些构造在cpu时间和内存占用方面可能是昂贵的。

注意,诸如多态之类的东西可能非常有价值-本质上是函数指针。如果发现需要它们,请明智地使用它们。

此外,良好的(精心设计的)异常处理可以使您的嵌入式应用程序比处理带有传统错误代码的应用程序更可靠。


2
严格来讲,C ++不是C的严格超集,但是在这种情况下,具体细节不是特别重要。
Arafangion 2010年

1

对于内存分配问题,我建议您使用Quantum Platform及其状态机方法,因为它会在初始化时分配您需要的所有内容。它还有助于减轻争用问题。

该产品可在C和C ++上运行。


1

有人说C编译器可以生成效率更高的代码,因为它们不必支持高级C ++功能,因此可以在其优化中更加主动。

当然,在这种情况下,您可能需要对两个特定的编译器进行测试。


1
相关信息:据我所知,strict关键字是C ++(也是C ++ 11)中唯一与优化相关的C构造。
约翰·伦德伯格2012年



1

您在C99中有内联。也许您喜欢ctor,但是正确设置Dtor的业务可能会很混乱。如果不使用C的唯一唯一原因是名称空间,那么我真的会坚持使用C89。这是因为您可能希望将其移植到稍有不同的嵌入式平台上。您稍后可以开始使用C ++编写相同的代码。但是请注意以下情况,其中C ++不是C的超集。我知道您说过您有C89编译器,但是无论如何都将C ++与C99进行比较,例如,第一项对于自K&R以来的所有C都是正确的。

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


1
不。我的意思是说在C语言中,您有(sizeof'a')== sizeof(int)。而在C ++中,你有1 ==的sizeof“一”

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,2009年

1
我不明白您对dtor的看法。关于它们的全部要点是,它们使您的其余代码了很多混乱。
jalf

1
+1,不确定为什么这个帖子得到了如此糟糕的说唱。但是我同意jalf的观点,在使用正确的(RAII)方式时,析构函数可以极大地简化代码。(你可以说,他们的“幕后工作”,但他们这样做只是东西,正确的代码会做手工反正。)
j_random_hacker

1
我认为我指出的内容与这个问题非常相关。我还坚持说dtor可能很困难,原因恰恰是它自动发生。我得了负分-那真的很危险。猜猜是因为我没有说“是的,GO C ++很棒”。

1

这取决于编译器。

并非所有嵌入式编译器都实现所有C ++,即使这样做,也可能无法避免代码膨胀(这对于模板来说总是有风险的)。用一些较小的程序进行测试,看看是否遇到任何问题。

但是,只要有一个好的编译器,不,没有理由不使用C ++。


1

只是想说没有系统具有“无限”资源。这个世界上的一切都是有限的,每个应用程序都应考虑资源使用情况,无论其ASM,C,JAVA还是JavaScript。可以确定分配几Mb的虚拟设备使iPhone 7,Pixel和其他设备显得异常庞大。无论您具有4kb还是40 Gb。

但是从另一方面来看,反对浪费资源是节省这些资源的时间。如果用1分钟的额外时间用C语言编写一个简单的东西来节省一些滴答声和几个字节,而不是使用已经实现,测试和分发的C ++,则可能需要花费1周的时间。何苦?就像买一个USB集线器。是的,您可以自己制作,但是会更好吗?更可靠?如果您算上时间更便宜?

只是想一想-您插座的电源也不是无限的。尝试研究它的来源,您会发现大部分来自燃烧的东西。能量和物质的定律仍然有效:没有物质或能量出现或消失,而是发生了变化。


0

我刚刚找到了一个如何使用ISO C ++进行嵌入式开发的示例,这对于在使用C ++或C时做出决定的人来说可能会很有趣。

它由Bjarne Stroustrup在他的主页上提供

要了解如何将ISO C ++用于认真的嵌入式系统编程,请参阅JSF飞机C ++编码标准


好吧,飞起来的东西往往拥有具有千兆字节RAM的PPC处理器。不是您的平均资源受限的嵌入式系统。
jakobengblom2

0

不同的答案发布到问题的不同方面:

“ malloc”

先前的一些答复对此进行了很多讨论。您为什么甚至认为该电话存在?对于真正的小型平台,malloc往往不可用,或者绝对是可选的。当您将RTOS置于系统底部时,实现动态内存分配通常很有意义-但在那之前,这纯粹是危险的。

没有它,您可以走得很远。想一想所有旧的FORTRAN程序,它们甚至都没有适当的局部变量堆栈...


0

全球有许多不同的控制器制造商,当您研究他们的设计和需要用来配置的指令集时,可能会遇到很多麻烦。汇编语言的主要缺点是依赖于机器/体系结构。要求开发人员全心投入那里列出的所有指令来完成针对不同控制器的编码,这确实是一个巨大的要求。这就是为什么C在嵌入式开发中变得越来越流行的原因,因为C足够高级,可以从与硬件相关的细节中抽象出算法和数据结构,从而使源代码可跨多种目标硬件,与体系结构无关的语言进行移植,并且非常易于转换并维护代码。但是我们确实看到了一些高级语言(面向对象),例如C,C ++,Python,Java等。


0

我建议使用限制和注释的C ++。

  1. 上市时间和可维护性。C ++开发更加轻松快捷。因此,如果您正处于设计阶段,请选择足以使用C ++的控制器。(请注意,某些大批量市场需要尽可能低的成本,而您在这种情况下无法做出选择。)

  2. 速度。C可以比C ++快,但是请确保此速度增益不大。因此,您可以使用C ++。开发算法,对其进行测试,并仅在需要时才使它们更快(!)。使用探查器来指出瓶颈,并以外部“ C”方式重写瓶颈,以达到C速度。(如果仍然缓慢地在ASM中实现该部分)

  3. 二进制大小。C ++代码更大,但是这里有一个很好的答案,它告诉了细节。无论使用C还是C ++编译器编译,给定C代码的已编译二进制文件的大小都将相同。“可执行文件的大小与语言几乎无关,但与项目中包含的库有关。” 用C ++去,但避免先进的功能,如streamsstringnewvirtual功能等评论让他们在最后的代码,因为大小限制之前,所有的库函数(基于答案)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.