ArduinoでのOOPとインライン


8

私はかなり長い間プログラミングをしていますが、ArduinoとAVRプログラミングは初めてです。これらのマイクロコントローラーのプログラミングに関して私が持っている主な質問は、オブジェクト指向クラスでのコードの設計と多くの例で見た従来のインラインプログラミングでは大きな違いがあるということですか?

言い換えれば、Arduino / AVRコントローラーの世界では、クラスを利用してメモリとパフォーマンスを節約したり、その逆を行ったりしますか?

たとえば、クラスがあるとします。

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の質問でした。

私がこれについて尋ねている理由は、できるだけ軽量である必要があるプロジェクトがあり、この環境で自分のプログラムをどのように設計すればよいのかわからないためです。


編集する

答えてくれてありがとう、これは物事に光を当てています。はっきりしない点が1つあります。

次のように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);
}

回答:


2

これらのマイクロコントローラーのプログラミングに関して私が持っている主な質問は、オブジェクト指向クラスでのコードの設計と多くの例で見た従来のインラインプログラミングでは大きな違いがあるということですか?

...

言い換えれば、Arduino / AVRコントローラーの世界では、クラスを利用してメモリとパフォーマンスを節約したり、その逆を行ったりしますか?

はい、CまたはC ++を使用する場合、Arduino / AVRなどの小規模な組み込みシステムでは大きな違いがあります。C ++では、コンパイラーの最適化のために、より多くの情報を提供できます。

OOPフレームワークを実装している場合は、プラットフォームまたはランタイムのC ++とクラスもソフトウェアアーキテクチャと再利用に役立ちます。でコサ OOP設計パターンの数は、アプリケーション・プログラマとデバイスドライバのプログラマの両方のインタフェースを達成するために使用されます。最も一般的なのは委任です。

抽象クラス、仮想メンバー関数、インライン化、およびテンプレートを使用すると、従来の実装よりも設置面積を小さくしてパフォーマンスを向上させることができます。例として、Cosa Pinクラスは、ArduinoコアよりもX5-X10高速であり、同時にフットプリントが小さくなっています。ベンチマークをご覧ください。

従来のC ++プログラミングから「学ぶ」ことの1つは、new / delete(malloc / free)の使用法です。SRAMサイズが数KBのヒープを使用すると、非常にリスクが高くなります。答えは、静的クラスとスタックベースのデータです。

OOPフレームワークアーキテクチャについてはまだまだ多くのことを述べていますが、これが最初の質問への回答に役立つことを願っています。

乾杯!


いい答えだ!動的メモリ(new / delete / malloc / free)を回避する方法について質問を更新しました。動的メモリ割り当てを使用しないという意見はありますか?クラス全体で共有する必要があるすべてのものをグローバルにする必要がありますか?それは私には正しく聞こえません、あなたがそれを助けることができるなら、私はいつもグローバルを使わないように教えられました。
アンディブラハム、2015

上記の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、2015

例; メンバーの数が可変である可能性があるBitSetクラスの設計を検討してください。明白な解決策は、必要なバイト数を計算し、new / mallocを使用することです。代わりの方法は、ストレージをパラメーターとしてBitSetコンストラクターに渡すことです。3番目の選択肢は、パラメータとして要素の数を持つテンプレートクラスです。これにより、必要なバイト数であるメンバー変数が許可されます。このプログラム変換のバリアントの詳細については、Cosa / BitSet.hhを参照してください。より多くの変化があります。
Mikael Patel、2015

私はUserInterfaceの例を更新しましたが、それは多かれ少なかれ正しいアプローチですか?これで、必要なことを実装する方法について非常によく理解できたと思います。
アンディブラハム

4

答えが見つからないのは、答えが「はい」と「いいえ」の両方だからです。

基本的なクラスのもの-メソッドなどでクラスを定義し、そこからオブジェクトをインスタンス化する-「バニラ」Cと比較して最終結果にほとんど違いはありません。コンパイラーの最適化は非常に優れているため、パフォーマンスはまったく同じです。はい、メソッド呼び出しごとに(の代わりに)追加のポインタを渡すため、メモリ使用量がわずかに増加する可能性がありfoo(int x)ますがfoo(MyClass *this, int x)、それは非常に小さいため、目立たないほどです。

大きな違いは、ポリモーフィズムやその他の高度なトピックを試してみるときに発生します。これらの複雑なプログラムの実行を開始するとき、コンパイラーは常に、必要な関数と不要な関数を計算できない場合があり、未使用の関数(「ガベージコレクション」)を切り捨てることができません。そのため、コードが大きくなる可能性があります。

それは遅いコードを意味するのではなく、ぶらぶらしていて何もしないコードのチャンクだけです。

より重要なのは、以前よりも動的メモリを適切に管理することです。そのような少量のメモリがあるため、ヒープは非常に小さく、その結果、非常に簡単に断片化されます。動的な作成とオブジェクト(の破壊new myClassdelete myClassObjectなど)が非常に悪いです。クラスオブジェクトは、静的に定義するか(グローバルスコープが最も一般的)、スタックに一時的に割り当てる必要があります(ローカルインスタンス)。そうでなければ、あなたはトラブルを求めています-そしてあなたは最初にそれが奇妙なことが起こっていることを知るでしょう(エラーレポートや例外はありません、あなたは見ます...)。


わかりましたので、このプログラミングの世界でこれを正しく理解している場合、クラスは真のOOPよりも組織的および移植性の役割に使用され、物事は動的ではなく静的かつ明示的に割り当てられるべきです。ありがとうございました。これは意味をなすものであり、なぜ私が例を見てきたのか、そして例がどのように書かれていないのかを説明しています。
アンディブラハム
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.