組み込みシステムで型抽象化を使用する必要がある場合

StackOverflow https://stackoverflow.com/questions/7084

  •  08-06-2019
  •  | 
  •  

質問

私はさまざまな組み込みシステムに取り組んできました。彼らは皆使ったことがある typedefs (または #defines) のような型の場合 UINT32.

これは、型のサイズをプログラマに知らせ、オーバーフローなどの可能性をより意識できるようになるため、優れたテクニックです。

ただし、システムによっては、コンパイラとプロセッサがプロジェクトの存続期間中変更されないことがわかっています。

では、プロジェクト固有のタイプを作成して適用するという決定には何が影響するのでしょうか?

編集私は自分の質問の要点を失うことができたと思いますが、多分それは本当に2つです。

組み込みプログラミングでは、インターフェイスに特定のサイズのタイプが必要な場合や、RAM などの制限されたリソースに対処する必要がある場合があります。これを避けることはできませんが、コンパイラの基本型を使用することを選択できます。

それ以外の場合、型の重要性はそれほど高くありません。
オーバーフローが発生しないように注意する必要があり、場合によってはレジスタとスタックの使用状況に注意する必要があります。それはあなたを導くかもしれません UINT16, UCHAR。次のような型を使用する UCHAR ただし、コンパイラ「綿毛」を追加することはできます。レジスターは通常より大きいため、一部のコンパイラーは、結果を型に強制的に組み込むコードを追加する場合があります。

i++;
になることができる
ADD REG,1
AND REG, 0xFF
それは不必要なことです。

したがって、私の質問は次のようにすべきだったと思います:-

組み込みソフトウェアの制約を考慮すると、全員が同じレベルの経験を持っているわけではない、多くの人が作業するプロジェクトに設定する最善のポリシーは何でしょうか。

役に立ちましたか?

解決

私は型抽象化をほとんど使用しません。主観性の高い順に並べた私の主張は次のとおりです。

  1. ローカル変数は、レジスタに収まるようにするという点で、構造体のメンバーや配列とは異なります。32b/64b ターゲットでは、ローカル int16_t コンパイラは /force/ overflow のセマンティクスに従って操作を追加する必要があるため、ローカル int と比較してコードが遅くなる可能性があります。 int16_t. 。C99 では、 intfast_t typedef 、私の知る限り、単純な int も同様にレジスタに収まり、確かに短い名前です。

  2. これらの typedef を好む組織は、ほぼ例外なく、そのうちのいくつかを使用することになります (INT32, int32_t, INT32_T, 、無制限)。したがって、組み込み型を使用する組織は、ある意味、名前のセットを 1 つだけ持つ方が良いと言えます。stdint.h や windows.h などの既存のものの typedef を使用してほしいと思います。ターゲットに .h ファイルがない場合、それを追加するのはどれほど難しいでしょうか?

  3. typedef は理論的には移植性を高めることができますが、私自身は、typedef から何も得られませんでした。32b ターゲットから 16b ターゲットに移植できる便利なシステムはありますか?32b ターゲットに移植するのが簡単ではない 16b システムはありますか?さらに、ほとんどの var が int であれば、新しいターゲットの 32 ビットから実際に何かを得ることができますが、 int16_t, 、そうはなりません。そして、移植が難しい場所では、とにかく手動による検査が必要になる傾向があります。ポートを試す前は、ポートがどこにあるのかわかりません。さて、あちこちに typedef があれば移植は簡単だと思う人がいるとしたら、移植するときが来たら (ほとんどのシステムでは起こりません)、コード ベース内のすべての名前を変換するスクリプトを作成してください。これは「手動による検査は不要」というロジックに従って機能するはずであり、実際にメリットが得られる時点まで作業が延期されます。

  4. さて、移植性が typedef の理論上の利点であるとすれば、 可読性 確かに排水溝に落ちます。stdint.h を見てください。 {int,uint}{max,fast,least}{8,16,32,64}_t. 。種類が豊富。プログラムには多くの変数があります。どれが必要なのかを理解するのは本当に簡単ですか? int_fast16_t そしてどれが必要か uint_least32_t?私たちは何度黙ってそれらの間で変換し、完全に無意味にしてしまったでしょうか?(特に BOOL/Bool/eBool/boolean/bool/int 変換が好きです。typedef を義務付ける秩序ある組織によって書かれたすべてのプログラムには、typedef が散りばめられています)。

  5. もちろん、C++ では、オーバーロードされた演算子などを使用してテンプレート クラスのインスタンス化で数値をラップすることで、型システムをより厳密にすることができます。これは、「クラス Number<int,Least,32> には、タイプ クラス Number<unsigned long long,Fast,64> の引数に対する演算子 + オーバーロードがありません。候補は...」という形式のエラー メッセージが表示されることを意味します。これを「読みやすさ」とは呼ばないでください。これらのラッパー クラスを正しく実装できる可能性は微々たるもので、ほとんどの場合、無数のテンプレートのインスタンス化がコンパイルされるまで待つことになります。

他のヒント

C99 標準には、標準サイズの整数型が多数あります。C99 をサポートするコンパイラ (gcc はサポートします) を使用できる場合、これらは次の場所にあります。 <stdint.h> プロジェクト内でそのまま使用できます。

また、組み込みプロジェクトでは、単位変換などに対する一種の「セーフティ ネット」として型を使用することが特に重要です。C++ を使用できる場合は、基になるスカラー型の操作としてコンパイルされる C++ 型システムによって (テンプレート経由で) 定義された物理ユニットで作業できるようにする「ユニット」ライブラリがいくつかあることを理解しています。たとえば、これらのライブラリでは、 distance_tmass_t ユニットが並んでいないからです。実際にはコンパイラエラーが発生します。

C++ や、コードを記述できる別の言語で作業できなくても、少なくとも C 型システムを使用すれば、そのようなエラーを目で確認することができます。(実際、これが Simonyi のハンガリー語表記の本来の目的でした。) コンパイラーが、 meter_tgram_t そのような型を使用してはいけないという意味ではありません。そうすれば、コードレビューはユニットエラーを発見する上でより生産的になります。

私の意見は、最小/最大/特定のサイズに依存しているかどうかです。 しないでください と仮定してください(言う) unsigned int 32バイトです - 使用します uint32_t 代わりに (コンパイラが C99 をサポートしていると仮定します)。

私はシステム API の定義に stdint.h 型を使用するのが好きです。なぜなら、stdint.h 型はアイテムの大きさを明示的に示すからです。Palm OS の昔、システム API は、非常に古典的な Mac OS から継承された「Word」や「SWord」のような、希望に満ちた型を多数使用して定義されていました。彼らは、代わりに Int16 という名前にクリーンアップを行い、特にシステム上の奇妙な 16 ビット ポインターの問題について、初心者にとって API を理解しやすくしました。Palm OS Cobalt を設計していたとき、stdint.h の名前と一致するようにこれらの名前を再度変更しました。これにより、さらに明確になり、管理しなければならない typedef の量が減りました。

MISRA 標準では typedef の使用が推奨 (必須?) されていると思います。

個人的な観点から言えば、typedef を使用すると、特定の型のサイズ (ビット/バイト単位) に関して混乱が生じません。私は、リード開発者が標準タイプを使用して両方の開発方法を試みているのを見てきました。int とカスタム型を使用する例:UINT32。

コードが移植性がない場合はほとんどありません 本物 typedef を使用すると利点があり、 しかし 私のように、両方のタイプのソフトウェア (ポータブル環境と固定環境) に取り組んでいる場合は、標準を維持し、カスタマイズされたタイプを使用すると便利です。少なくともあなたが言うように、プログラマは自分が使用しているメモリの量をよく知っています。考慮すべきもう 1 つの要素は、コードが別の環境に移植されないという確信がどの程度あるかということです。ハードウェア エンジニアが突然ボードを変更しなければならなくなったため、プロセッサ固有のコードを変換する必要があるのを見たことがあります。これは良い状況ではありませんが、カスタム typedef のせいで、さらに悪いことになっていた可能性があります。

一貫性、利便性、読みやすさ。「UINT32」は、一部のシステムで同等の「unsigned long long」よりも読み書き可能です。

また、コンパイラとプロセッサはプロジェクトが存続するまで修正される可能性がありますが、そのプロジェクトのコードは別のプロジェクトで新たな命を吹き込まれる可能性があります。この場合、データ型が一貫していると非常に便利です。

組み込みシステムが何らかの理由で問題を抱えている場合、 安全性が重要なシステム (または同様の)、それは強いです アドバイスした (必要でない場合) プレーン型ではなく typedef を使用します。

として TK. 以前に言いました、 ミスラ-C そうするための(勧告)ルールがあります。

規則 6.3 (勧告): 基本的な数値型の代わりに、サイズと符号付きを示す typedef を使用する必要があります。

(MISRA-C 2004 より。これは MISRA-C 1998 のルール #13 (adv) です)


この分野では、C++ にも同じことが当てはまります。例えば。 JSF C++ コーディング標準:

AV ルール 209 UniversalTypesファイルが作成され、開発者が使用できるすべてのsta ndardタイプを定義します。種類には次のものがあります。[uint16、int16、uint32_t など]

使用する <stdint.h> PC 上での単体テストのためにコードの移植性が向上します。

すべてのテストを行っている場合、この問題はかなり深刻な問題になる可能性がありますが、それでもターゲット システムでは問題が発生します。 int 突然 16 ビット長になりました。

私は変かもしれませんが、整数型には ub、ui、ul、sb、si、sl を使用します。おそらく 16 ビットの「i」は少し古いように思えますが、私は uw/sw よりも ui/si の見た目の方が好きです。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top