Arduino的OOP与内联


8

我已经编程了一段时间了,但是我是Arduino和AVR编程的新手。我对这些微控制器进行编程的主要问题是,在面向对象的类中设计代码与在许多示例中看​​到的更传统的嵌入式编程之间是否存在重大差异?

换句话说,在Arduino / AVR控制器世界中,使用类或反之亦然可以节省内存和性能吗?

假设我们有一个Class:

class SomeClass(){

private:
   int x;
   int y;

public:
   void foo();
   void bar();
}

SomeClass thisClass;
thisClass.foo();
thisClass.bar();

以更内联的方式设计程序是否会提高性能或内存,例如:

int x;
int y;

void foo(){ /*** Do something ***/};
void bar(){ /*** Do more stuff ***/};

我尝试在Stack Exchange和Google上进行一些搜索,但找不到完全可以找到的答案,我正在寻找的最能找到的就是此Stack Exchange问​​题。

我之所以这样问,是因为我有一个项目,它需要尽可能的轻巧,而且我不清楚在这种环境下应该如何设计程序。


编辑

谢谢您的回答,这为您提供了启示。我还不太清楚一件事。

假设您正在设计一个使用u8glib的类,如下所示:

class UserInterface{
private:
   U8GLIB_ST7920_128X64 Display;

public:
   UserInterface();
}

您将如何使用“动态内存”解决问题:

UserInterface::UserInterface(){
   UserInterface::Display = U8GLIB_ST7920_128X64(LCD_E_PIN, LCD_RW_PIN, LCD_RS_PIN, U8G_PIN_NONE);
}

Answers:


2

我对这些微控制器进行编程的主要问题是,在面向对象的类中设计代码与在许多示例中看​​到的更传统的嵌入式编程之间是否存在重大差异?

...

换句话说,在Arduino / AVR控制器世界中,使用类或反之亦然可以节省内存和性能吗?

是的,在小型嵌入式系统(如Arduino / AVR)中使用C或C ++有很大的不同。C ++允许为编译器优化提供更多信息。

如果要实现OOP框架,则平台或运行时C ++和类也可以帮助实现软件体系结构和重用。在Cosa中,许多OOP设计模式用于为应用程序程序员和设备驱动程序程序员实现接口。最常见的是委派

与传统的实现相比,使用抽象类,虚拟成员函数,内联和模板可以帮助实现更低的占用空间和更高的性能。例如,Cosa Pin类的速度比Arduino内核快X5-X10,同时占用空间更小。请参阅基准

从传统的C ++编程中“学习”的一件事是对new / delete(malloc / free)的使用。使用堆只有几KB的SRAM大小是非常危险的。答案是静态类和基于堆栈的数据。

关于OOP框架体系结构还有很多要说的,但是我希望这有助于回答您的最初问题。

干杯!


好答案!我更新了我的问题,询问如何避开动态内存(新的/删除的/ malloc /免费的)。您是否有关于不使用动态内存分配的信息?是否需要在整个课程中共享的所有内容都是全球性的?这对我来说听起来不对,我总是被教导不要在可以帮助的情况下使用全局变量。
安迪·布拉汉姆

在上面的UserInterface示例中简短说明。Display实际上是对象组合(不是引用/指针),因此您不需要新的对象。您确实需要启动显示器。UserInterface构造应如下所示。UserInterface::UserInterface() : Display(LCD_E_PIN, LCD_RW_PIN, LCD_RS_PIN, U8G_PIN_NONE) { ... }。必需的Display构造函数参数应传递给UserInterface构造函数。
Mikael Patel 2015年

OOP完全是关于封装,隐藏数据的,因此共享应为最小值(零)。目标是或多或少仅具有多个相互作用的全局静态对象。他们持有并隐藏了全球状态。对于对象,成员数据是非动态本地状态。为了实现这一目标,您再次需要一套技巧。程序转换。
Mikael Patel

一个例子; 考虑可能具有可变数量的成员的BitSet类的设计。显而易见的解决方案是计算所需的字节数并使用new / malloc。另一种选择是将存储作为参数传递给BitSet构造函数。第三种选择是使用元素数量作为参数的模板类。这允许一个成员变量为必需的字节数。请参阅Cosa / BitSet.hh了解有关此程序转换变体的更多详细信息。还有更多的转变。
Mikael Patel

我更新了UserInterface示例,这或多或少是正确的方法?我想我现在对如何实现所需的功能已经有了很好的理解。
安迪·布拉汉姆

4

您找不到答案的原因是因为答案是肯定和否。

对于基本类的东西(使用方法等定义类并从中实例化对象),最终结果与“原始” C几乎没有区别。编译器的优化是如此出色,现在的性能是相同的。是的,由于每次方法调用都要传递一个额外的指针(而不是foo(int x)您拥有foo(MyClass *this, int x)),因此内存使用量可能会略有增加,但是它是如此之小以至于不引起注意。

当您开始研究多态性和其他高级主题时,就会出现很大的差异。当开始执行这些复杂的程序时,编译器并不总是无法确定哪些功能是必需的,哪些不是必需的,并且它也无法切出未使用的功能(“垃圾收集”)。因此,您可能最终会获得更大的代码。

这并不意味着代码速度会变慢,只是周围徘徊的代码块什么也做不到。

最重要的是要比过去更好地管理动态内存。由于内存量非常小,因此堆非常小,因此很容易将其碎片化。动态创建和对象(破坏new myClassdelete myClassObject等等)是非常糟糕的。类对象确实需要静态定义(在全局范围内是最常见的)或临时分配在堆栈上(本地实例)。否则,您会自找麻烦-首先您会知道这是一件奇怪的事情(没有错误报告或异常,您会看到...)。


好吧,如果我在当今的编程世界中正确理解了这一点,那么类将被用作组织和可移植性的角色,而不是真正的OOP,并且应该静态地,显式地而不是动态地分配事物。非常感谢,这很有道理,并解释了为什么我一直看到示例,以及为什么没有写成示例。
安迪·布拉汉姆
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.