7

プロトタイプが次の関数を見たことがあります。

int myfunc(void** ppt)

この関数は、C ファイルで a = myfunc(mystruct **var1); として呼び出されます。

mystruct は、構造体の 1 つの typedef です。

これは MSVC6.0 ではコンパイル エラーなしで動作しますが、他の C コンパイラでコンパイルすると、この関数が呼び出された場所でエラー メッセージが表示されます。

タイプ mystruct ** の引数はタイプ void ** のパラメーターと互換性がありません

myfunc() の引数は void** として保持されます。これは、メモリ割り当てのためにさまざまな構造体変数型で呼び出される一般的な malloc のような関数のように見えるためです。

  1. C 標準/任意の C コンパイラで許可されている void ** などの型はありますか?
  2. これを修正するにはどうすればよいですか? 【関数呼び出しの引数を にキャストしてみmystruct**ましたがダメでした】

-広告

4

6 に答える 6

22

comp.lang.c FAQは、質問4.9でこの問題に詳細に対処しています。要するに、彼らは、任意のポインタからポインタを;にキャストすることは厳密には移植可能ではないと言います。void **彼らはさらに、「このようなコードは機能する可能性があり、推奨されることもありますが、同じ内部表現を持つすべてのポインター型に依存しています(これは一般的ですが、普遍的ではありません)」と説明しています。彼らは続けて、「あなたが遊ぶどんなvoid **値もどこかの実際の値のアドレスでなければなりませんvoid *;のようなキャスト(void **)&dpはコンパイラをシャットダウンするかもしれませんが、移植性がないかもしれません(そしてあなたが望むことさえしないかもしれません)」。

したがって、次のようなコードを使用して、目的の動作を安全に/移植可能に実現できます。

some_type *var1 = foo();
void *tmp_void_ptr = (void *)var1;
myfunc(&tmp_void_ptr);
于 2008-10-30T15:51:31.790 に答える
8

void** 有効ですが、エラー メッセージに基づいて、おそらく次のように引数を明示的にキャストする必要があります。

mystruct **var1;
x = myfunc ((void**) var1);

これは、myfunc関数が型を期待しているためvoid**です。他のポインターにvoid*暗黙的にキャストできますが、ダブルポインターの場合はそうではありません-明示的にキャストする必要があります。

于 2008-10-29T10:03:33.850 に答える
3

mystruct**コンパイラが からに自動的にキャストできないのには理由がありますvoid**

次のコードを検討してください。

void stupid(struct mystruct **a, struct myotherstruct **b)
{
    void **x = (void **)a;
    *x = *b;
}

その行がへのポインターのみを配置する必要がある場所に aへのポインターを配置しようとしている場合でも、コンパイラーは行内の from からmyotherstruct*への暗黙のキャストについて文句を言いません。void**x = *bmyotherstructmystruct

間違いは実際には前の行にあり、「ポインターを配置できる場所へのポインターmystruct」を「何かへのポインターを配置できる場所へのポインター」に変換しています。これが、暗黙のキャストがない理由です。もちろん、明示的なキャストを使用する場合、コンパイラは、ユーザーが何をしているのかを知っていると想定します。

于 2008-10-29T10:44:15.483 に答える
1

この質問は少し紛らわしいです。しかし、はい、void **確かに合法で有効な C であり、期待どおり「ポインターへのポインター」を意味しますvoid

呼び出しの例についてはよくわかりません。引数(「mystruct **var1」)は意味がありません。var1タイプが の場合mystruct **、呼び出しは と読みますa = func(var1);。これはタイプミスの可能性があります。

キャストは機能するはずですが、 にキャストする必要がありますvoid **。これは、関数が期待するものだからです。

于 2008-10-29T10:04:23.600 に答える
0

はい、void **完全に受け入れられ、特定の状況では非常に役立ちます。また、宣言void **fooとを指定するとvoid *bar、コンパイラはfooが指すオブジェクトのサイズを認識します(ポインタを指し、心配する必要のないいくつかの古いプラットフォームを除いて、すべてのポインタは同じサイズです)。バーが指すオブジェクトのサイズはわかりません(任意のサイズのオブジェクトを指す可能性があります)。したがって、ポインタに対してポインタ演算を安全に実行できますが、ポインタに対しては実行できvoid **ませvoid *。最初に、のような他の何かにそれらをキャストする必要がありますchar *。GCCを使用すると、そのふりをvoid *char *て同等のふりをすることができ、それぞれが1バイトのサイズのオブジェクトを指しますが、これは非標準であり、移植性がありません。

于 2008-10-29T20:04:02.217 に答える
0

汚いように見えるかもしれませんが、void ** を使用しないと問題を解決できない場合があります。

于 2008-10-29T10:04:27.717 に答える