6

Cでcuuxをスポークするライブラリを構築しているとしましょう。

Quuxを正常にスポークするには、次の2つの状態変数が必要です。

static int quux_state;
static char* quux_address;

/* function to spork quuxes found in a file, 
   reads a line from the file each time it's called. */
void spork_quux(FILE*);

そのデータをグローバル変数として保存すると、一度に1つのクライアントのみがキューをスポークできます。そうしないと、状態変数が2番目の呼び出し元によって破壊され、災害が発生する可能性があります。

問題は、Cでリエントラントライブラリを設計するための最良の方法は何ですか?

私は以下のケースを楽しませましたが、満足のいく結論には至りませんでした。

次の場合、問題はクライアントを各状態に関連付ける方法です。

/* library handles all state data allocation */
static int* quux_state; 
static char** quux_address;

次の場合、クライアントは状態を混乱させる可能性があり、非常に望ましくありません

/* let each client store state */
typedef struct { int state; char* address; } QuuxState; 
QuuxState spork_quux(FILE*);

では、これを適切に行う方法は?

4

3 に答える 3

21

構造体を使用しますが、定義をクライアントに公開しないでください。

すなわち。.hヘッダーファイルに次のように配置します。

typedef struct QuuxState QuuxState;

QuuxState *spork_quux(FILE*);

および.c実装ファイル内:

struct QuuxState
{
    int state;
    char* address;
};

QuuxState *spork_quuxFILE *f)
{
    QuuxState *quuxState = calloc(1, sizeof(*quuxState));
    if (!quuxState)
        return NULL;

    quuxState->state = ....;

    ........

    return quuxState;
}

このアプローチの利点は次のとおりです。

  1. すべてのクライアントコードを再コンパイルせずに構造体の内容を変更できます
  2. クライアントコードはメンバーにアクセスできません。quuxState->stateはコンパイラエラーを出します
  3. QuuxState構造は引き続きデバッガーに完全に表示されるため、値を簡単に確認したり、ウォッチポイントを設定したりできます。
  4. キャスティングは必要ありません
  5. 返される型は特定の型であるため、正しいものが渡されていることをコンパイラーがチェックします(void *ポインターと比較して)

唯一の欠点は、メモリのブロックを割り当てる必要があることです。ただし、ライブラリが重要なことを実行していると仮定すると(ファイルI / Oを実行している場合、それは確かに重要です)、単一のmallocのオーバーヘッドはごくわずかです。

上記の関数の名前を「QuuxSpork_create」のような名前に変更し、行ごとの作業の実行と完了後の状態の破棄を処理する関数をさらに追加することをお勧めします。

void QuuxSpork_readLine(QuuxState *state)
{
    ....
}

void QuuxSpork_destroy(QuuxState *state)
{
    free(state);
}

このように大まかに機能するライブラリのランダムな例は、POSIXスレッドライブラリであるpthreadsです。

于 2010-07-13T13:39:11.610 に答える
3

構造体を使用しますが、それが構造体であることをクライアントに伝えないでください。不透明なポインタ(void *、さらには空のダミー構造体へのポインタ)を渡し、必要に応じてキャストし直します。

于 2010-07-13T13:29:45.003 に答える
1

ほとんどのライブラリ関数がこれを処理する方法は、必要なデータ型で状態情報をユーザーに返すことです。あなたの場合、構造体。(strtokとstrtok_rを比較してください)。これは、ユーザーに返すべき前例となると思います。ボイド*が機能します。きれいに見えるようにtypedefすることもできます。

さらに、strtok_rは、状態へのポインターを返すのではなく、コマンドライン引数を編集することによってこれを行います。私が使用するリエントラント関数は、同様の形式に従うと思います。もちろん、私の脳はかなりクレイジーなCコードによって歪められています。

void spork_quux(FILE*, QuuxState **);
于 2010-07-13T13:49:13.263 に答える