2

次の場合に最適なソリューションは何ですか:

  • 私たちの API はユーザーに構造を返します
  • ユーザーがその内容を読めるようにしたい
  • 他の API 関数に渡される可能性があり、その内容は正しいはずなので、ユーザーに変更してほしくありませんか?
4

6 に答える 6

2

関数は、const 構造体へのポインターを返すことができます。それで:

  • 呼び出し元は、const 構造体へのポインターを介して構造体を変更することはできません。AC 実装では、このルールを適用する必要があります。
  • 呼び出し元が const 構造体へのポインターを API の別の関数に渡す場合、C 規則では、その関数が const 構造体へのポインターを非 const 構造体へのポインターに変換することを許可します。構造体がconst として定義されていない場合(たとえば、非 const として作成されたが、構造体へのポインターが const 構造体へのポインターに変換された場合)、関数は新しく変換されたポインターを介して構造体を変更できます。非 const 構造体に。
  • C の規則では、呼び出し元がこれと同じ変換と変更を行うことも許可されています。明らかに、発信者はこれを行うべきではありません。発信者がそうしないという善意に依存しています。したがって、この手法は、返されたポインターによる不注意な変更を防ぎますが、変換されたポインターによる悪意のある変更は防ぎません。

さらに先に進むには、構造体の不完全な宣言のみを呼び出し元に提供することができます。これは、その名前のみを明らかにし ( のようにstruct foo;)、その内容を定義しません ( のようにstruct foo { int x;… };)。呼び出し元が構造体の不完全な宣言しか持っていない場合、呼び出し元は構造体へのポインターを受け取り、それを格納して引数として渡すことができますが、それを使用して構造体にアクセスすることはできません (変換などの異常な手段による場合を除きます)。別の型へのポインターに、または構造体の独自の定義を提供することによって)。

呼び出し元が構造体の不完全な宣言しか持たないが、構造体の内容を使用できる必要がある場合は、構造体へのポインターをパラメーターとして受け取り、構造体内から情報を返す追加の関数を提供する必要があります。

于 2013-08-13T11:39:53.030 に答える
1

ユーザーが構造体の内容にアクセスするのを止める方法はありません。これが必要な場合は、不透明な値を返し、API を追加してこれらの不透明な値の 1 つを取得し、そこから個々の値を返す必要があります。

于 2013-08-13T10:25:20.473 に答える
1

この関数を使用するたびに、この構造体のコピーを作成し、コピーを使用して返すことができると思います。

このように、関数が呼び出されるたびに、新しいコピーが作成されます。

また、ユーザーmallocにメモリを与えて API にアドレスを与えることができます。API はアドレスmemsetを埋めるために使用するだけなので、ユーザーはデータの使用が終了した後にメモリを解放できます。

またopaque pointer 、構造体をどこにでも保存したくない場合は、 a を使用できます。

PS:コマンドで3番目の提案を言うと、反対票を獲得しますが、他の人がこれを彼の答えに追加して賛成票を獲得するのを見ますが、最初にこの行がありません。

于 2013-08-13T09:54:04.523 に答える
1

ここでの回答を拡張するには、 opaque の使用を示唆していますstruct

C では、ユーザーがデータにアクセスするのを防ぐ方法はほとんどありません。パブリック API のパラメーターと戻り値として処理する場合、データを非表示にしたり、ユーザーがそのデータにアクセスしないように契約で義務付けstructsたりする方法がいくつかあります。

おそらく opaque の最も明白な一般的な使用法struct<stdio.h> FILE *. 標準ライブラリを使用してファイルの読み取り/書き込み/クエリを実行するときはいつでもstruct FILE *fwrite. 構造を調べると、プラットフォーム間で同じ実装であることが保証されていないため、未定義の動作が発生します。

ユーザーが一部のデータを変更できるようにして、他のデータを変更できないようにする場合は、次のようにします。

typedef struct 
{
    void * _my_private_data; //KEEP OUT
    char * name;
    int count;
    //etc
}my_api_type;

次に、ユーザーに公開されるすべての関数呼び出しの最初のパラメーターを定義して、それらのいずれかを取ることができますstructs

my_api_type set_internal_flag(my_api_type * obj, int flag);

プライベート データが隠されていることを確認すると、API 関数の背後にある構造体をどのように定義するかに関係なく、void *仕様が変更されても互換性が維持され、何かが更新されたときにユーザーがコードを変更する必要がないことを実装で保証できます。

于 2013-08-13T10:45:11.580 に答える