4

私は、すべてのバイトがカウントされる 8051 のプロジェクトに取り組んでいます。そのため、通常は使用しないいくつかのグローバル変数を使用しています。ポインターを関数に渡す通常の方法では、ここでオーバーヘッドが大きくなりすぎます。

通常の戻り値に加えて、関数の結果を通知するために単一ビット変数 ( Cのコンパイラ固有の拡張機能) を使用する関数がいくつかあります。

bit global_error_flag = 0;
bit global_data_ready_flag = 0;

unsigned char A_Function (void) {
    // Do some stuff

    if ( badness ) {
        global_error_flag = 0;
        global_data_ready_flag = 1;

        return 0;
    }

    if ( data_is_ready_use ) {
        global_data_ready_flag = 1;
    }

    return a_value;    
}

void Other_Function (void) {
    unsigned char c;

    c = A_Function();

    if( global_error_flag) {
        // Do error stuff here.
    }
    else
    if( global_data_ready_flag ) {
        // Do data processing here.
    }
    global_error_flag = 0;
    global_data_ready_flag = 0;

}

テクニックが悪かったので、コードをより明確にする方法はありますか?

どの関数呼び出しにこれらのフラグを設定する副作用があるかをどのように示すべきですか? コメントは十分ですか?API を示すために関数に名前を付ける必要がありますか (準ハンガリー式)? そのような呼び出しをマークするためにマクロを使用する必要があります:

#define FUNCTION_SETS_FLAGS(code) (code)

FUNCTION_SETS_FLAGS( c = A_Function() );

他のアイデアはありますか?

4

9 に答える 9

6

「ハンガリー語」と呼ぶかどうかに関係なく、規則を使用することは、これをオフハンドでマークするための最良の方法です。スタイル的には、少なくとも私にとっては、空の #define よりも、ある種の命名プレフィックスの方が望ましいでしょう。

これは実際にはかなり一般的だと思います。S60 プログラミング環境では、たとえば関数が例外をスローすることを示すために、多くの従来のタグを関​​数に使用していることを私は知っています。

于 2009-04-13T22:13:30.977 に答える
3

私は博士号を取得しました Javaの同様の問題について。私はあなたがしてはいけない一つのことをあなたに言うことができます:あなたは実際にそれを読んでいる誰かに依存しているので、ドキュメントに依存しないでください。ユーザーが副作用について学ぶためにドキュメントを読む必要があることを示すために、メソッド名にいくつかのヒントを追加する必要があります。あなたが何かを選び、それと一致しているなら、あなたはおそらく最もチャンスがあります。

于 2009-04-13T23:11:22.663 に答える
3

あなたのグローバルは明確にするためにラベル付けされています。これは良いスタートです。

理想的には、間違った場合にコンパイルされないものが必要です。つまり、マクロとコメントは機能しません。

関数の命名規則に固執します-必ずしもハンガリー語ではありませんが、 のようなものA_Function_Returns_Flags、またはそれを考えることができれば冗長ではありません。

于 2009-04-13T22:13:57.513 に答える
3

関数がグローバル変数に影響を与えることだけを言いたい場合は、単純な (ハンガリー語の) 接頭辞が役立つかもしれません。

しかし、影響するすべてのフラグについて言及したい場合は、関数ヘッダーを使用するのがおそらく最善の方法です。たとえば、

  /*************************************************************************
     * FUNCTION    : <function_name>
     * DESCRIPTION : <function description> 
     * PARAMETERS  : 
     *  Param1  - <Parameter-1 explanation>
     *  Param2  - <Parameter-2 explanation>
     *  Param3  - <Parameter-3 explanation>
     * RETURN      : <Return value and type>
     * GLOBAL VARIABLES USED: 
     *  Global1 - <Global-1 explanation>
     *  Global2 - <Global-2 explanation>
     *  Global3 - <Global-3 explanation> 
  *************************************************************************/
于 2009-04-14T01:22:10.493 に答える
2

これはあまり役に立ちませんが、GCC には、ユーザーが望むこととはの方法があります。つまり、副作用のない関数をマークします。constおよびpureアトリビュートを参照してください。これはドキュメンテーションよりも最適化のためであると考えられています: 与えられた関数がその引数以外のデータを検査しないことをコンパイラーが認識している場合、ループ不変コード モーションなどのよりスマートな最適化を実行できます。

于 2009-04-13T22:22:58.803 に答える
2

マクロを使用して関数をシミュレートし、より多くのパラメーターを持たせることができます。


unsigned char _a_function(void);

#define A_Function(ret_val) (*(ret_val) = _a_function(), !global_error_flag)

...
unsigned char var;
/* call the function */
if (!A_Function(&var))
{
    /* error! */
}
else
{
    /* use var */
    var++;
}

私はそれをコンパイルしようとしていないので、これが機能するとは言えませんが、そうすべきだと思います。

于 2009-04-14T08:50:10.790 に答える
0

まだ行っていない場合は、sourceforge で sdcc プロジェクトを確認することもできます。これは、8051 もターゲットとする組み込み開発に使用することを特に意図した C コンパイラです。さらに、コンパイラは多くのカスタムをサポートしています。また、個人的には、開発チームは新しい拡張機能やその他の関連する機能要求のアイデアに対して非常にオープンで反応が良いことがわかりました。

于 2009-05-22T18:27:39.953 に答える
0

最初に、これらのフラグのそれぞれに対して 1 つのプロデューサーと 1 つのコンシューマーのみが存在するようにコード化しようとします。次に、必要な場合にのみフラグをクリア/設定します。副作用を示すことに関しては、関数の上の標準ヘッダー、doxygen スタイルで十分なはずです。

    // Function func
    // Does something
    // Consumes ready_flag and  sets error_flag on error.

    int func()
    {
        if (ready_flag)
        {
            //do something then clear the flag
            if (some_error)
                error_flag = x;
            ready_flag = 0;
        }
        //don't mess with the flags outside of their 'scope'
        return 0;
    }

一方、エラー フラグと準備完了フラグが相互に排他的である場合は、バイト (またはバイト/レジスタ内のビット) を使用して、準備状況またはエラー状態を示すことができます。

エラーの場合は 0、準備ができていない/エラーがない場合は 1、準備ができている/エラーがない場合は 2 (または -1、0、1 など)

IIRC、標準の 8051 命令セットは単一ビットでは動作しないため、(さまざまな) フラグにバイト全体を使用しても、パフォーマンスが大幅に低下することはありません。

于 2009-04-13T23:04:01.573 に答える
-2

これらのグローバル変数に本当に固執する必要がある場合は、関数の引数としてそれらへの参照を期待することで、関数がそれらを変更する可能性があることを明確にすることができます:

unsigned char A_Function (bit *p_error_flag, bit *p_data_ready_flag)
{
  ...
}
于 2009-04-16T06:58:07.127 に答える