7

私は自分の大学のグループ シニア プロジェクトに取り組んでおり、コードを動作させる際に大きなハードルに遭遇しました。

8 ビット Atmel マイクロコントローラー用のコンパイラーは、new または delete 演算子をサポートしておらず、C++ STL もサポートしていません。C でプログラムすることもできましたが、これまでに行ったことのない A* アルゴリズムを実装する必要があります。私は最初に C を試しましたが、純粋な C をこれまでやったことがないことにすぐに気付きました。構造体と関数を使用してオブジェクトをモデル化しようとすると、速度が低下します。これは、よりクリーンな C++ 構文に慣れているためです。

とにかく、私のコンパイラの欠点の正確な表現はここにあります: http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_cplusplus

それらを克服し、引き続き C++ を使用するために、次の可能性を検討しました。1) 何も割り当てず、テンプレートを使用してスタック上に固定配列を生成します。2)オブジェクトにスペースを割り当てたら、オブジェクトのコンストラクターを呼び出すためのハックを割り当てて見つけます。new は演算子ではないため、配置 new はオプションではありません。3) C を使って、それを吸い上げてください。それはマイクロコントローラーです。4) おそらく $$$ の費用がかかる、より優れたコンパイラを見つけてください。

2 番目のオプションは最も難しいですが、このコードをどのように記述できるかという点で最大の見返りがあります。ただし、間違った場合のデバッグは非常に苦痛になると思います。スタック上にオブジェクトを作成し、それらのビットを割り当てられたスペースにコピーし、オブジェクトのビットをゼロにしてデストラクタを呼び出さないようにすることを考えています。そのためには、unsigned char ポインターと sizeof 演算子を使用してビットに直接アクセスし、バイト カウントを取得します。

それはひどいように聞こえますし、確実に機能するかどうかはわかりませんが、検討しています。vtables が問題になる可能性があることはわかっていますが、vtables は 8 ビットのマイクロコントローラーにすぎないため、vtables を使用するつもりはありません。

4

8 に答える 8

23

ツールと戦わないでください。組み込みシステム用のコンパイラが C コンパイラしかない場合は、C を学びましょう - 難しいことではありません。かなり単純なプログラミングの問題を解決するためだけに、この 2 つの言語の粗末なバージョンを作成しようとしても、涙を流すだけです。

別の見方をすると、組み込みプラットフォームが C コンパイラさえサポートせず、アセンブラのみをサポートしているとしたら、最初の衝動は、座ってアセンブラで C++ コンパイラを作成することでしょうか? 代わりに、座ってアセンブラーを使用して課題を完了することを学んでください.C++コンパイラー(またはCコンパイラーでさえ)を書くことは、あなたの時間をまったく不適切に使用し、ほぼ確実に失敗に終わります.

于 2009-04-19T14:20:51.093 に答える
10

念のため、オブジェクトのビットをゼロにしても、デストラクタが呼び出されるかどうかには影響しません (コンパイラがこの動作を可能にする特別な癖を持っていない限り)。これをテストするには、デストラクタにいくつかのログ ステートメントを記述するだけです。

何も割り当てないようにプログラムを構成することは、おそらくシステムが設計された方法です。私はこれまで組み込みシステムを扱ったことがありませんでしたが、ランタイム環境には動的メモリがほとんどないため、動的メモリの使用を思いとどまらせる経験豊富な組み込みショップを読んだことがあります。


ただし、必要に応じて、placement new を引き続き使用できます。ヘッダーがない場合は<new>、私のバージョンの GCC でヘッダーから直接関連する行を以下に示します。

// Default placement versions of operator new.
inline void* operator new(std::size_t, void* __p) throw() { return __p; }
inline void* operator new[](std::size_t, void* __p) throw() { return __p; }

// Default placement versions of operator delete.
inline void  operator delete  (void*, void*) throw() { }
inline void  operator delete[](void*, void*) throw() { }

配置の新規/削除を使用するすべてのソースファイルに含まれるヘッダーファイルのどこかにそれを貼り付けます。

これをテストするサンプル ファイル:

#include <cstdio>
#include <new>

int
main(int argc, char** argv)
{
    typedef char const* cstr;
    char foobar[16];
    cstr* str = new (&foobar) cstr(argc > 1 ? argv[1] : "Hello, world!");
    std::puts(*str);
    str->~cstr();
}

私のバージョンの GCC では、これはまったく使用libstdc++されません (使用されている場合-fno-exceptions)。


mallocこれを(プラットフォームがこれを提供する場合)と組み合わせたい場合は、次のようにします。

#include <cstdio>
#include <cstdlib>

inline void* operator new  (std::size_t n) {return std::malloc(n);}
inline void* operator new[](std::size_t n) {return std::malloc(n);}
inline void  operator delete  (void* p) {std::free(p);}
inline void  operator delete[](void* p) {std::free(p);}

int
main(int argc, char** argv)
{
    typedef char const* cstr;
    cstr* str = new cstr(argc > 1 ? argv[1] : "Hello, world!");
    std::puts(*str);
    delete str;
}

これにより、 を使用しなくても、使い慣れた標準のnew/を使用できます。deletelibstdc++

幸運を!

于 2009-04-19T14:31:10.723 に答える
6

あなたは最適とは言えない視点から問題に取り組んでいると思います。

ハードウェアに焦点を当てるのではなく、コンパイラ (またはその欠如) に焦点を当てています。

主な質問に対する最も可能性の高い答えは、「ハードウェアが C++ のすべてをサポートしていないため」です。組み込みハードウェア (マイクロコントローラー) は、ハードウェア設計のカスタマイズ (メモリ マップ、割り込みハンドラー、I/O など) で注目されています。

私の意見では、最初にマイクロコントローラのハードウェア ブックに時間を費やして、デバイスの内外を学習する必要があります。つまり、どのように設計され、どのような主な目的で使用されるかです。高速メモリ操作用、高速 I/O 処理用、A/D タイプの作業用、信号処理用に設計されたものがあります。マイクロコントローラーの種類によって、マイクロコントローラー用に作成されたアセンブラー命令が決まり、それによって、より高レベルのコンパイラーが効率的に実行できることが決まります。

これが重要な場合は、時間をかけてアセンブラも調べてください。設計者が何を重要と考えているかがわかります。また、高レベルのコンパイラからどれだけ得られるかについても多くのことを教えてくれます。

一般に、マイクロコントローラーは C++ をサポートしていません。これは、設計が実際にはオブジェクトや凝ったメモリ処理 (C++ の観点から) を気にしないためです。それは可能ですが、マイクロ環境でコンストラクターとデストラクター (および「新規」と「削除」) を機能させるために、四角い穴に丸いペグを打ち込もうとすることがよくあります。

このユニット用の C コンパイラがある場合は、それを祝福と考えてください。優れた C コンパイラは、多くの場合、優れた組み込みソフトウェアを作成するのに「十分すぎる」ものです。

乾杯、

-リチャード

于 2009-04-19T15:46:22.773 に答える
4

これらのツールがないからといって、C++ の恩恵を受けられないわけではありません。プロジェクトが十分に大きい場合、オブジェクト指向設計へのアクセスだけで十分な動機になる可能性があります。

「new」がサポートされていない場合は、おそらく、ヒープとスタックを自動的に区別する意味がないためです。これは、メモリ構成が原因である可能性があります。また、メモリ リソースが非常に制約されているため、非常に慎重な割り当てのみが意味をなす可能性もあります。独自の「新しい」演算子を絶対に実装する必要がある場合は、Doug Lea の mallocを採用することを検討してください。彼は同様の状況でアロケーターを始めたと思います (C++ の新しいものを再実装する)。

私は STL が大好きですが、STL がなくても便利なことはできます。プロジェクトの範囲によっては、配列を使用したほうがよい場合があります。

于 2009-04-19T14:28:03.120 に答える
2

Embedded-C++標準の奇妙なバージョンを実装した同様のコンパイラがありました。コンストラクタを呼び出すものがあり、ほとんどの場合operator new、デストラクタが呼び出されました。コンパイラ/ランタイムベンダーは、エンジニアの便宜のために、実装して使用しました。問題は、ローカルオブジェクトのデストラクタが呼び出されないことを彼らが言及しなかったことです。trycatchsetjmplongjmpthrow

とにかく、私たちのグループは、誰かが標準C ++のように動作するアプリケーションを作成した後、コードベースを継承しました。RAII技術と他のすべての優れた機能を使用します。代わりに、多くの人がオブジェクト指向Cと呼んでいるものに書き直すことになりました。弾丸を噛んでストレートCで書くことを検討することをお勧めします。コンストラクターの代わりに、明示的に呼び出される初期化メソッドを使用します。デストラクタは、明示的に呼び出される終了メソッドになります。Cですぐに模倣できないC++はそれほど多くありません。はい、MIは苦痛です...しかし、単一の継承は非常に簡単です。いくつかのアイデアについては、このPDFをご覧ください。それは私たちが取ったアプローチをほぼ説明しています。メソッドをどこかに書き留めておけばよかったのに...

于 2009-04-19T15:09:23.177 に答える
1

私の A* チュートリアル Web サイトで役立つコードが見つかるかもしれません。これをサポートするために私が書いたコードは STL を使用していますが、STL サポートを取り除くのは簡単なはずです。さらに、ゲーム コンソールで STL を高速化するために作成したプール アロケータ (fsa.h) が含まれています。これは C++ コードですが、元々は C から移植したものであり、他の方法で行うのは難しいとは思いません。このコードは 10,000 人以上の人々によってテストされているため、出発点として適しています。

私が使用している STL 構造を置き換えることは、ベクトルに限定されているため問題ありません。ヒープ関数 (make_heap と push_heap) を使用して、ベクトルの 1 つを優先キューとして使用します。それを、C で実装されたプライオリティ キューを持つ私の古い C コードに置き換えることができます。(これは1つの割り当てのみを行うため、それをメモリの予約領域へのポインターに置き換えることができます.

ヘッダーのこのコード フラグメントでわかるように、C コードの主な違いは、this ポインターやオブジェクトがないことです。そのため、コードは通常、オブジェクト ポインターを最初の引数として受け取ります。

void PQueueInitialise( PQUEUE *pq, int32 MaxElements, uint32 MaxRating, bool32 bIsAscending );
void PQueueFree( PQUEUE *pq );
int8 PQueuePush( PQUEUE *pq, void *item,  uint32 (*PGetRating) ( void * ) );
int32 PQueueIsFull( PQUEUE *pq );
int32 PQueueIsEmpty( PQUEUE *pq );
void *PQueuePop( PQUEUE *pq, uint32 (*PGetRating) ( void * ) );
于 2009-04-19T16:34:53.720 に答える
0

埋め込み作業を行うとき、メモリ制約のためにCランタイムをリンクすることさえできませんでしたが、ハードウェアにはDMA(動的メモリアロケータ)命令があったので、そのハードウェアで独自のmallocを作成しました。ハードウェアにも同様の機能がある可能性があります。あなたはmallocを書いて、それからmallocに基づいて新しいものを書くことができます。

とにかく、最終的には99%のスタック割り当てを使用し、いくつかの制限により、適切な場所に構築することで、リサイクルする静的オブジェクトを設定しました。これは私に良い解決策かもしれません。

于 2009-04-19T15:22:07.793 に答える
0

コンパイラの制限を考慮して、最初にデスクトップ コンピューターで記述し、デバッグし、完全に動作することを確認してから、組み込み環境に移行してみませんか?

于 2009-04-19T14:11:55.263 に答える