6

さまざまな出力機能 (デジタル出力、シリアル、アナログなど) を持つ組み込みシステムに取り組んでいます。これらの関数を制御する多くの変数を渡すためのクリーンな方法を見つけようとしています。

それらすべてを頻繁に渡す必要はありませんが、入力データ (この場合は TCP ネットワークから) を読み取り、データを解析する関数が必要でした (IE、3 番目のバイトには8 つのデジタル出力の状態 (そのバイトのどのビットが高いか低いかに応じて)) を変数に入れ、プログラムの他の場所で使用できるようにします。

その関数を main() 関数とは別にしたかったのですが、そうすると、書き込み先の 20 ほどの変数へのポインターを渡す必要がありました。変数をグローバルにできることはわかっていますが、関数に渡すことで、関数がその変数をいつ編集できるかを明確にすることで、デバッグを容易にしようとしています。

私の最良のアイデアは構造体であり、それにポインターを渡すだけでしたが、特にそれらすべてに一度にアクセスする必要がある関数は実際には1つしかないため、より効率的な方法があるかどうかはわかりませんでした。この一連の状態変数に格納される情報の一部のみを必要とします。

とにかく、編集が必要な関数間で一度に多くの変数を送信するきれいな方法はありますか?

4

5 に答える 5

6

それへのポインターで構造体を使用することは、本当に良い賭けです。コードを書くのは少し長くなるかもしれませんが、見栄えは良いでしょう。値渡しで構造体を渡すことはできますが、参照渡しではデータのコピーが回避されます。

もう 1 つの方法は、構造体で構成される構造体を作成することです。次に、全体、1 つまたは 2 つのみ、または構造体の個々の要素を渡すことによって、各関数に渡すデータをより選択的にすることができます。

typedef struct a {
  struct b {
    int b1;
    int b2;
  } b_s;
  struct c {
    int c1;
    int c2;
  } c_s;
} a_s;
于 2010-04-12T21:12:36.330 に答える
3

これは「パラメータ ブロック」の古典的な使用法です。よく知られている構造体への単なるポインタです。

利点は次のとおりです。 特定のパラメーターへのアクセスはアドレスとオフセットであるため、効率的です。デバッグの容易さ (すべてのパラメーターを 1 つの「印刷」で確認できます)。局所性 (適切にキャッシュされます); スタック可能な一連の呼び出しに簡単に変換できますが、スタックの下にある特定の関数が必要とする可能性のあるパラメーターを簡単に知ることはできません。

欠点には次のようなものがあります。関数呼び出しを見ても、呼び出し先にとってどのパラメーターが重要かを判断することはできません。知る必要があるか、その関数のソースを掘り下げる必要があります。特に、呼び出された関数がブロックを変更できるようにすると、副作用が発生しやすくなります (悪い、悪い、悪い!)。カップリングが増加します (すべての関数がすべてのパラメーターを参照できるため、誘惑につながる可能性があります...)

于 2010-04-12T21:45:03.940 に答える
0

構造体へのポインタを渡すことは、通常、「クリーンな」方法です。データ構造をインテリジェントに定義することで、この方法にパワーと柔軟性の両方を与えることができます。たとえば、データ構造を考えてみましょう。

struct func_params {
    int type;
    union {
        struct {
            int    port;
            int    direction;
            long   target_addr;
        } digital_io;
        struct {
            int    channel;
            long   sample_rate;
        } analog_in;
        struct {
            int    channel;
            int    async;
            int    hold_output;
        } analog_out;
        struct {
            int    port;
            int    direction;
            int    encoding;
        } serial_io;
    };
};

次のようなもので関数を定義します

my_function (struct func_params* pStruct, size_t length)

関数を使用するときは、最初に、データ構造に加えて、関数に送信する可能性のある可変長データのサイズ(たとえば、ポートを送信するためのデータ)を含むのに十分な大きさのバッファーを作成します。データバッファの最初の部分は、定義した構造で構成されます。残りのバッファ(length-sizeof(struct func_params)バイト)は、データを保存する場所になります。関数は構造体メンバーを読み取り、type構造体の残りの部分を解釈する方法を決定し、構造体を処理した後、可変長データセクションを解釈する方法を決定できます。

これは、あなたが考えていたものよりも少し複雑かもしれません。組み込みの世界では、多くの通信プロトコル(SCSIなど)は、ヘッダーの後にこのような可変長データセクションを送信することによって通信します。これにより、関数にクリーンなインターフェイスが提供され、関連情報が適切にバンドルされ、呼び出し元のパラメーターを変更せずに、将来的に関数を簡単に変更できるようになります。

于 2010-04-12T21:39:27.000 に答える
0

構造体が最善の策だと思います。特定の関数ですべての変数が必要ない場合は、メンバーの 1 つだけを関数に渡すことを選択できます。個々のビットを設定する必要がある場合は、その 3 番目のバイトのビットフィールドを利用することもできます。もちろん、このビットフィールドは構造体のメンバーにすることもできます。

于 2010-04-12T21:14:22.813 に答える
0

私がすることは、構造体を受け入れるようにそれらすべてを書くことです。プログラムが機能した後、効率が問題になる場合は、簡単に戻って、1 つまたは 2 つの変数のみを使用する関数を変更して、変数への変数のみをパラメーターとして受け入れるようにする必要があります。

于 2010-04-12T21:19:52.987 に答える