小尺寸微控制器上的C ++

时间:2011-04-19 02:25:46

标签: c++ oop embedded

在我看来,人们总是回避,或者更确切地反对在微控制器上使用C ++,但我不能为我的生活找出原因。如果您远离大型C ++库(例如STL)并且您不尝试使用RTTI或异常处理等复杂功能,那么C与C ++之间是否存在明显差异?虚拟继承是否会对复杂性或占用空间产生巨大影响?我认为这是一个额外的内存,但大多数复杂性将由编译器处理,但我再也不知道很多关于那个黑魔法。我只是不明白为什么人们非常坚持使用C,除了少数几个没有C ++编译器的架构(如果有的话)。看起来模块化和模板的好处是不费脑子的,即使你不能使用你的cin或cout。

我问,因为我正在为一些我想做的爱好项目做一些研究。理想情况下,我希望严格地使用C ++来实现很好地模块化的能力,而C语言的“SomeClass_SomeMethod(struct object * this ...)”是“面向对象”的方法。 (我更喜欢这些项目的对象Pascal,但是对这种语言的支持并不完全是明星......)我宁愿避免转向功能更强大的微处理器,因为A.对于我正在做的项目,我不需要大量的资源..我不打算写60个状态卡尔曼滤波器或编码1080p视频B.(真正的踢球者)我想使用DIP和QFP封装中提供的处理器。我希望能够在没有焊接或烘烤任何东西的情况下进行原型制作。

有什么想法吗?

6 个答案:

答案 0 :(得分:20)

在C ++中,你基本上只需支付你使用的内容,而不是C编译代码,并且一些附加功能是免费的。

针对小型目标的一些C ++编译器的最大问题是可用C ++实现的完整性或C ++编译器的可用性。

多年来,EETimes / Embedded.com就此主题撰写了大量文章:

这些文章的大部分内容是,您不一定要在嵌入式系统中使用所有的C ++,而是根据内存,速度和各种功能的确定性来衡量或解释成本。您使用的部分取决于应用程序的性质(例如,它是否具有实时约束),以及目标平台的可用资源和性能。

答案 1 :(得分:10)

C ++委员会就此主题写了一篇(免费)technical report

答案 2 :(得分:5)

当然它变化很大。

我不会在“小”MCU上使用虚拟继承。我根本不会使用堆。

在该领域看起来最具吸引力的C ++特性是名称空间(在网络MCU的程序之间共享软件组件),模板(例如,通过I / O端口参数化协议),以及{{1}等一般语义改进并且不那么粗略的积分促销。

但是,至少在我对专业嵌入式设备的简短尝试中,一个合适的C ++编译器根本不存在,而且可用的糟糕的编译器每年花费数千美元。

GCC是可用于嵌入式平台的功能最强大,最广泛使用的C ++编译器。但是,它的平台支持非常不平衡。如果您拥有无限的资源,EDG会宣称他们将为Comeau提供优于“您的”嵌入式平台的支持。

答案 3 :(得分:3)

C ++人不断问“你为什么使用C而不是C ++”。我想知道为什么我应该使用C ++而不是C。

首先,必须认识到这两种语言都是古代,并且它们都具有可怕的语法。辩论似乎常常集中在“你应该使用C ++,因为C ++是现代的而C是老的”。实际上,争论的焦点是人们最喜欢的恐龙肉。人们不是要求一种适合嵌入式的现代语言,而是提倡使用C ++,它从来就不是一种奇怪的临时混合语言,具有C兼容性,等待一些更好的语言被发明。

其次,有一个神话说C ++是面向对象而C不是。流行语面向对象归结为三件事:

  • 1)具有自主物体的模块化设计,与其他物体没有紧密耦合。这是任何程序的一个非常重要的属性。
  • 2)数据的私有封装和数据范围的缩小。这是任何计划的一个相当重要的属性。
  • 3)类的多态性:继承其他类并在继承时表现不同的类。多态性非常有用,但在小型嵌入式系统中却少得多。

1)可以在C和C ++中完全实现,这是程序设计而不是语言语法的问题。到目前为止,这是最重要的OO属性!不幸的是,任何语言标准都没有告诉您如何设计程序。 C ++中没有任何东西会自动导致更好的模块化设计,它完全掌握在程序员手中。

2)可以在C和C ++中实现。两种语言都缩小了数据范围。在C中,私有封装是通过在文件范围变量上使用static关键字的有些可怕的语法来完成的。在C ++中,使用private / protected更加优雅。

3)可以在C和C ++中实现。这两种语言都有可怕的语法。在C语言中,您可以使用结构和函数接口来实现它。在C ++中,您可以通过遗产和使功能“虚拟”以不太可怕的方式完成。然而,C ++语法和所需的实现仍然是一个大问题,虽然比C方式好一点。

这两种语言都不会以漂亮,优雅的方式为您提供与OO相关的内容。 C ++从一些不那么狡猾的语法中获得了什么,当你开始涉及未定义/未指定/实现定义的行为时它会丢失。

似乎整个OO论证并不是什么大不了的事,C ++在OO方面并不是一个巨大的改进。那么在我的嵌入式系统中我还需要C ++中还有什么呢?有一点很突出:标准化的内联汇编语法。对于嵌入式系统,这可能是C ++对C的最大优势。

除此之外,excpetions,STL,模板,RTTI,overator重载,函数重载等等都是或多或少无用的功能。

然后最终,现实让你大打折扣:根据标准设法完全实现C ++的嵌入式编译器极少(如果有的话)。

答案 4 :(得分:2)

  

C与C ++之间真的有明显区别吗?

根据我的经验,RAM的使用存在很大差异。

例如:我目前正在为具有512KB FALSH和64KB RAM的ARM uC开发C ++。 RAM使用率应小于30kB,但是两倍,因为每个const都在RAM中结束。 这是因为几乎不可能(至少使用GCC和ARM目标)说服编译器在FLASH中保留const类成员。实现这一目标的唯一方法是使用无构造函数的类,将所有const成员声明为public并使用聚合初始化列表。

更糟糕的是,C ++不允许在初始化列表中命名成员,就像在纯C中一样:

struct St {  int b;  int a[3];  };

static const struct St st_array[2] =
{
    [1] = { .a = {1,2,3,},  .b = 10, }, // deliberately disordered to
    [0] = { .b = 8,  .a = { 4,5,6,}, }, // illustate the value of names.
};

所有C编译器都会将这些常量放入“常量数据”段(在FLASH中)。

在C ++中你必须这样做:

class ClassA  // cannot have constructor or destructor
{
public:  // const data cannot be private for aggregate initialization
    const int b;
    const int a[3];
private:
    int priv_fn(int i);
public:
    int pub_fn();
};

static ClassA classA_array[2] = 
{   
    { 3, { 8, 9,10,}, },  // aggregate initialization 
    { 4, { 9,10,11,}, },  // better get the order right!!!
};

根据您的编译器,即使这可能也不能保证常量保持在FLASH中。

是的,我知道,使用C ++ 0x你可以使用构造函数的初始化程序列表,这就是我正在做的事情,但是当你有一个在运行时调用的构造函数时,所有初始化都变为动态。

technical report(感谢MSalters)确认了这一点:

7.1.2构造函数和ROMable对象 通常,必须动态初始化具有构造函数的类的const对象。 但是,在某些情况下,如果静态分析可以执行编译时初始化...

最重要的是,这样的静态分析不是由我可用的任何编译器完成的,如果我必须将自己限制为具有公共consts且没有初始化器命名的无构造函数的类,那么我也可以在plain(和object)中编写 - 导向的)C。

答案 5 :(得分:1)

对于“小足迹”,我担心的是代码膨胀。如果您的代码需要驻留在一小块硬件中,那么模板类的实例

 std::vector<int>

有自己的一套说明,分开来自

 std::vector<double>

因此,每次创建新类型的向量时,编译器都会有效地复制粘贴代码以创建新类,并使用自己的一组函数复制每条指令。如果您对存储指令的内存量有限制,则可能会非常快速地出现问题。对于非嵌入式系统的人来说,它会成为问题。

但就运行时性能而言,我认为你没有多少to worry about。在某些情况下,例如排序,C++ outperforms C