マイクロコントローラー用の効率的なCコードの作成に関するリソース [閉まっている]


15

ここでは深刻な助けが必要です。プログラミングが大好きです。最近、C言語の本(K&Rなど)や記事/フォーラムをオンラインでたくさん読んでいます。Linuxコードを調べてみました(どこから始めたらいいのか迷っていましたが、小さなライブラリを覗いてみると助けになりましたか?)。

私はJavaプログラマーとしてスタートしましたが、Javaでの作業はかなり乾燥しています。プログラムが大きくなりすぎた場合は、クラスでスライスし、さらに関数に分割します。ガイドラインは、コードを読みやすくし、コメントを追加します。情報の隠蔽とOOPテクニックを使用します。そのうちのいくつかはまだCに適用されます。

私は今Cでコーディングしており、これまでのところ、プログラムを何らかの方法で動作させています。多くの人がパフォーマンス/効率、アルゴリズム/設計、最適化、保守性について話します。一部の人々はもう一方を強調しますが、プロではないソフトウェアエンジニアにとっては、次のようなことをよく耳にします。

私の質問は次のとおりですリソースを無駄にせずに 8ビットマイクロコントローラー用のコードを書く予定です。私はJavaのバックグラウンドから来ているので、物事はもう同じではないことを知っています...リソース/ブック/リンク/ヒントは大歓迎です。パフォーマンスとサイズが重要になりました。8ビットマイクロコントローラー向けの効率的な(ベストプラクティス内)Cコードのリソース/コツですか?

また、inline assemblyマイクロコントローラーの標準に近いだけでなく、重要な役割を果たします。しかし、すべてに適用される効率の一般的な経験則はありますか?

たとえば、: register unsigned int variable_name;charいつでも好まれます。または、 uint8_t 大きな数字が必要ない場合に使用します。

編集:すべての答えと提案をありがとうございました。知識を共有するための皆の努力に感謝します。


2
これは、x86プロセッサーではあまりよくありませんが、マイクロコントローラーでは、パフォーマンスを最後まで落とすためには、代わりにアセンブリを使用することをお勧めします。
宮坂

3
@Rei:手作りのアセンブリは、使用されるメモリが少なく、最新のCコンパイラよりも高速です。Cで(必要に
応じて

1
@mattnz現代では、どのくらい新しいことを話しているのですか?正直なところ、私はマイクロコントローラー用のコードを10年近く書いていません。
宮坂

2
1つの簡単なヒント:ミクロンコントロールでは、「より単純な場合はより高速」であるというのが一般的に真実です。複雑なチップ(ARM以上)では、ハードウェアは非常に多くの最適化を実行するため、テストするまでわかりません。
ハビエル

1
@ReiMiyasakaメンテナンス費用の大幅な増加。優れたCコンパイラは、経験豊富なプログラマとほぼ同じコードを生成できます。

回答:


33

私は20年以上の組み込みシステムを所有していますが、ほとんどは8および16マイクロです。あなたの質問に対する簡単な答えは他のソフトウェア開発と同じです-あなたが必要だとわかるまで最適化しないでください、そしてあなたが最適化する必要があるものを知るまで最適化しないでください。最初に信頼性が高く、読みやすく、保守しやすいようにコードを書きます。時期尚早な最適化は、組み込みシステムの問題ではありませんが、それ以上ではありません

「リソースを無駄にせずに」プログラムを作成するとき、あなたの時間をリソースと見なしますか?そうでない場合は、誰があなたの時間をあなたに支払っていますか?組み込みシステムの設計者が選択しなければならないのは、ハードウェアのコストとエンジニアリング時間のコストです。100ユニットを出荷する場合、100,000ユニットでより大きなマイクロを使用し、1ユニットあたり1.00ドルの節約は、1人年のソフトウェア開発(市場投入までの時間、機会費用などを無視)と同じで、100万ユニットで開始しますリソース使用量に執着しているためにROIを取得しますが、多くの組み込みプロジェクトは100万を販売するように設計されているため(製造コストが低く、初期投資が高い)、100万点を達成することはできず、到着する前に破綻しました。

そうは言っても、(小さな)組み込みシステムでは、遅くするだけでなく、予期しない方法で動作を停止するため、考慮し、注意する必要があるものがあります。

a)スタック-通常、スタックサイズは小さく、スタックフレームサイズは限られています。スタックの使用率を常に把握しておく必要があります。注意してください、スタックの問題は最も陰湿な欠陥のいくつかを引き起こします。

b)ヒープ-ヒープサイズが小さいため、不当なメモリ割り当てに注意してください。断片化が問題になります。これら2つを使用すると、実行時に何を行うかを知る必要があります。OSが提供するページングにより、大規模システムでは発生しません。すなわち、mallocがNULLを返す場合、それをチェックし、何をしますか。すべてのゼニアオイは、チェックとハンドラー、コードの肥大化が必要ですか?ガイドとして-代替手段がある場合は使用しないでください。ほとんどの小規模なシステムは、これらの理由でダイナミックメモリを使用しません。

c)ハードウェア割り込み-これらを安全かつタイムリーに処理する方法を知る必要があります。また、安全な再入可能コードを作成する方法を知る必要があります。たとえば、C標準ライブラリは一般的にリエントラントではないため、割り込みハンドラー内で使用しないでください。

d)アセンブリ-ほとんどの場合、時期尚早の最適化。Cができないことを実現するには、せいぜい少量(インライン)が必要です。練習として、手作りのアセンブリに小さなメソッドを(最初から)記述します。Cでも同じことを行います。パフォーマンスを測定します。Cはより高速になり、読みやすく、保守しやすく、拡張可能になると確信しています。演習のパート2では、アセンブリとCで有用なプログラムを作成します。
別の演習として、Linuxカーネルに関するアセンブラーの量を見てみましょう。

それを行う方法を知る価値はありますが、1つまたは2つの一般的なマイクロの言語に習熟する価値さえあります。

e)「register unsigned int variable_name」、「register」は、70年前半(40年前)に、命令ではなく、コンパイラへのヒントであり、常にヒントでした。2012年には、コンパイラが非常にスマートであり、micros命令セットが非常に複雑であるため、キーストロークの無駄です。

Linuxのコメントに戻ります-ここでの問題は、私たちが100万台だけでなく、何億もの話をしているということです。人間的に可能な限り最適化するためのエンジニアリング時間とコストは価値があります。非常に優れたエンジニアリングの実践の良い例ではありますが、ほとんどの組み込みシステム開発者にとっては、Linux kernalが要求するのと同じくらい慢になるのは商業的な自殺でしょう。


4
mattnz:これは、.stackexchangeサイトで最も美しい回答の1つです。
アーメドマスード

1
この答えを改善することはできません。私は、アセンブリコードだけを挿入すると、ほとんどのパフォーマンスのために理にかなっていないことを追加される場合がありますが、それはCで行うのは簡単ではないかもしれないI / Oチップやその他のハードウェアのトリックを突っついのようなもののために意味を作ることができる
マイクDunlavey

@mattnzよく答えてくれてありがとう。+1
AceofSpades

1
@MikeDunlaveyアセンブラーは、正確なタイミングのために必要になる場合があります。....その後3clockサイクルのための電圧の高6は、低-ちょうど使用はI / OピンのNTSCビデオを生成するために叩いビットことビデオオーバーレイを終え、タイミングに関するものである
マーティンベケット

@マーティン:それは完全に理にかなっています。そのレベルでコーディングしてから長い時間がかかります。
マイクダンラベイ

3

あなたの質問(「リソースを無駄にしない」)は一般的すぎるため、多くのアドバイスをするのは難しいです。文字通り、リソースを無駄にしたくない場合は、一歩下がって、何かを行う必要があるかどうか、つまり他の方法で問題を解決できるかどうかを評価する必要があります。

また、有用なアドバイスは制約に非常に依存しています-どのようなシステムを構築し、どのようなCPUを使用していますか?ハードリアルタイムシステムですか?コードとデータ用にどのくらいのメモリがありますか?すべてのC演算(特に、乗算と除算)をネイティブにサポートしますか?より一般的には、データシート全体を読んで理解してください。

最も重要なアドバイス:シンプルに保ちます。

例:複雑なデータ構造(ハッシュ、ツリー、場合によってはリンクリスト)を忘れ、固定サイズの配列を使用します。より複雑なデータ構造の使用は、配列が遅すぎることを測定により証明した後にのみ保証されます。

また、過剰設計しないでください(Java / C#開発者がやる傾向があります):あまり階層化することなく、簡単な手続き型コードを記述します。抽象化にはコストがかかります!

グローバル変数とgoto [例外がない場合のクリーンアップに非常に便利]を使用するという考え方に慣れてください;)

割り込みを処理する必要がある場合は、再入可能性についてお読みください。再入可能コードの作成は非常に簡単です。


3

mattnzの答えに同意します -ほとんどの場合。私は30年以上前に8085でプログラミングを開始し、その後Z80を使用して8031に素早く移行しました。推測は、私が一周したことを意味します。記録のために、いくつかの主要なマイクロプロセッサメーカーのFAEは、意図的なコードの再利用のためにオブジェクト指向の方法ではあるが、まだアセンブラを使用していると述べることができます。

承認済みの回答に表示されないのは、ターゲットプロセッサのタイプや提案されたアーキテクチャの議論です。メモリが限られている0.50 $ 8ビターですか?パイプライン処理と8Megのフラッシュを備えたARM9コアですか?メモリ管理コプロセッサー?OSは搭載されますか?while(1)ループ?100000ユニットの初期生産稼働を備えた消費者向けデバイスですか?大きなアイデアと夢を持つスタートアップ企業ですか?

現代のコンパイラーは最適化の素晴らしい仕事をすることに同意しますが、私はデバッガーを停止せず、生成されたアセンブリコードを表示してフードの下で何が起こっているのかを確認するプロジェクトに30年間取り組んだことがありません(明らかに、パイプライン化と最適化が作用するときの悪夢です)、アセンブリの知識は重要です。

そして、CEO、エンジニアリング担当副社長、ガロンをクォートコンテナーに詰め込んだり、ソフトウェアソリューションを使用してハードウェアの問題を解決することで.05 $を節約したりしない顧客はいませんそうでしょうか?)メモリ(コードまたはデータ)の最適化は常にカウントされます。

私のポイントは、プロジェクトを純粋なプログラミングの観点から見ると、より狭い範囲のソリューションを賢明に得られるということです。Mattnzにはそれがあります-動作させてから、より速く、小さく、良く動作させますが、コーディングについて考える前に、要件と成果物に多くの時間を費やす必要があります。


こんにちはGio、投稿に不要なHTMLを使用しないようにして、代わりにMarkdown構文を使用してください。以下のために<br />あなただけのEnterキーを押すと、段落のちょうどそれらの間に空白行を残すことができます。また、別の回答を参照する場合は、リンクを追加してください。この時点では、回答は数個しかありませんが、多くのページに分散してさらに存在する可能性があり、どの回答を意味するかは明確ではありません。改訂履歴をチェックして、編集内容を確認してください。
ヤニス

@Gio他の重要な要因について言及してくれてありがとう。+1 :)
AceofSpades

+1-私の答えの素晴らしい展開。
マッテンツ

1

Manttzの回答は、「ハードウェアに近い」プログラミングを行う方法についての最も重要なポイントを非常によく示しています。これは結局、Cが意図していることです。

ただし、「Class」という厳密なキーワードはCには存在しませんが、ハードウェアに近い場合でもCでのオブジェクト指向プログラミングの観点から考えるのは非常に簡単です。

あなたはこの答えを考慮するかもしれません:この点を説明するCプログラムのためのオブジェクト指向のベストプラクティス

Cで適切なオブジェクト指向コードを作成するのに役立つリソースを次に示します。

a。Cでのオブジェクト指向プログラミング
b。これは人々がアイデアを交換するのに適した場所
ですc。ここに完全な本があります

私があなたに提案したい別の良いリソースは:

すばらしいコードシリーズを書いてください。これは2巻の本です。最初の本は、低レベルの作品で機械の非常に重要な側面をカバーしています。2冊目の本は「低レベルを考える-高レベルを書く」です。


1

いくつか問題があります。まず、このプロジェクト/コードを移植可能にしたいですか?移植性はパフォーマンスとサイズを犠牲にしますが、実装するプラットフォームとタスクの選択肢は、過剰なサイズとパフォーマンスの低下に耐えることができますか?

はい、8ビットマシンでは、符号なし整数やショートの代わりに符号なし文字を返すことは、パフォーマンスとサイズを改善する1つの方法です。同様に、16ビットマシンでは、符号なしのショートと32ビットマシンの符号なしintを使用します。ただし、たとえば、引き継いでいるシステム全体で移植性を確保するためにどこでも符号なしintを使用した場合(たとえば、ARMが最低電力、最小のデバイス市場に押し下げた場合)、そのコードは巨大なrom hogであることがわかります8ビットマイクロ。もちろん、intまたはshortまたはcharなしでunsignedを使用し、コンパイラに最適なサイズを選択させることもできます。

インラインアセンブリだけでなく、アセンブリ言語全般。インラインアセンブリは非常に移植性が低く、単にasm関数を呼び出すよりもうまく書くのが困難です。はい、コールのセットアップとリターンを書き込みますが、開発、メンテナンス、および制御が容易になります。ルールはまだ適用されますが、本当に必要な場合にのみasmで記述し、この領域でコンパイラの出力が問題であると結論付けて、手作業で行うことでどれだけのパフォーマンス向上が得られるかを結論付けてください。次に、移植性と保守に戻ります。Cとasmを混合し始めるとすぐに、Cとasmを混合するたびに移植性が損なわれる可能性があります。あなたが現在開発している製品であり、他の誰かが道を維持する必要があります。その分析を行うと、インラインに進む必要があるか、ストレートアセンブリに進む必要があるかどうかが自動的にわかります。私はこの分野で25年以上の経験があり、毎日Cとasmの混合物を書き、ハードウェア/ソフトウェア層で/でライブを行い、インラインasmは決して使用しません。コンパイラー固有の努力に値することはめったにありません。可能な限り(ほとんどどこでも)コンパイラー非固有のコードを作成します。

質問全体の鍵は、Cコードを逆アセンブルすることです。コンパイラーがコードで何をするかを学び、時間をかけて、必要に応じて、asmに頼ることなく、コンパイラーを操作して目的のコードを生成することを学ぶことができます。時間があれば、コンパイラを操作して複数のターゲット間で効率的なコードを生成し、asmに頼らずにコードの移植性を高めることができます。16ビットおよび32ビットシステムでは符号なしcharの方がコストが高くなります(一部のアーキテクチャでは、アウト、いくつかはいけない)。

一部の8ビットマイクロコントローラーはすべて、コンパイラーにとって非常に使いにくいものであり、優れたコードを生成するコンパイラーはありません。これらのデバイスのコンパイラ市場を作成して、それらのターゲット向けの優れたコンパイラを作成するための十分な需要はありません。 。この世界に参入するarmとmipsは、多くの作業を行ったコンパイラー、かなり良いコードを生成するコンパイラーなどのターゲットを持っているため、そのモデルを変更しています。 asmにドロップダウンしなければならないが、それほど頻繁ではない場合、コンパイラーに何をしたいかを伝えるのは、使用しないよりもずっと簡単です。コンパイラを操作することは、見苦しい、判読できないコードではないことに注意してください。実際、それは反対の、きれいで、わかりやすいコードであり、おそらくいくつかのアイテムを再配置します。関数のサイズとパラメーターの数を制御することにより、コンパイラーの出力に大きな違いが生じます。コンパイラまたは言語のKhee-whiz機能(KISS)を避け、単純な愚かさを保ち、多くの場合、はるかに優れた高速なコードを生成します。


生産する製品の種類は明記していません。非常に大量、低マージン、または異常なマージンをもつ特定のニッチ市場のいずれかだと思います。これは、小さな8ビットマイクロと手作りのアセンブラー、またはより大きなマイクロとCを使用する必要があるかどうかをビジネスレベルで決定するために重要です。あなたの(削除された?)コメントに応えて必要以上のマイクロから始めて、BOMコストが問題になる場合にのみ修正します)市場投入までの時間、運用コスト、および償却された開発コストにより、BOMに10セントまたは20セントを追加できます。
マッテンツ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.