2009-05-11 21 views
1

次のコードは、互換性のない型について警告します。このコードを解決する適切な方法は何ですか?構造体と関数呼び出しの動的配列f(const struct_type * const data [])

おかげホタルブクロの回答に基づいて編集された

typedef struct a_struct struct_type; 

void f(const struct_type *const data[], unsigned n); 

void test(unsigned n) 
{ 
    struct_type **v; 

    assert(n); 
    v = malloc(n * sizeof(struct_type *)); 
    /* fill v with new struct_type (with a malloc per entry) */ 
    f(v, n); <- WARN on v 
} 
+2

警告を受け取っているのは、どのラインですか? – LeopardSkinPillBoxHat

答えて

4

の宣言には、最初にconstと書かれています。

void f(struct_type *const data[], unsigned n); 
/*...*/ 
f(v, n); 

を使用してみてください、あなたは同じ警告を取得することはありません。あなたはf

void f(const struct_type *const data[], unsigned n); 
/*...*/ 
f((const struct_type * const *) v, n); 

を呼び出すときに別の方法として、あなたはvを唱えこれは少し直感に反するが、Cには、あなたはpointer-to-pointer-to-constためpointer-to-pointer-to-nonconstを渡すことはできません。彼らは特別な例外を作成してにpointer-to-nonconstを渡すことができました。

はここでよくある質問質問"Why can't I pass a char ** to a function which expects a const char **?"です:

は、あなたが使用することができますpointer-to-Tpointer-to-const-Tが期待されている(いずれかのタイプTのため)。しかし、修飾されたポインタ型でわずかなミスマッチを許すルール(明示的例外)は再帰的には適用されず、トップレベルでのみ適用されます。 (const char **pointer-to-pointer-to-const-charであり、例外は、従って、適用されない。)

もしconst char **ポインタにchar **値を割り当てることができない理由は幾分あいまいです。 const修飾子がまったく存在するとすれば、コンパイラはconstの値を変更しないという約束を守るのを手助けしたいと考えています。それでchar *const char *に割り当てることができますが、それ以外の方法ではありません。constに追加するのは明らかですが、それを取り除くのは危険です。ただし、割り当ての以下のより複雑な一連の行ったとします。3行目で

const char c = 'x';  /* 1 */ 
char *p1;   /* 2 */ 
const char **p2 = &p1;  /* 3 */ 
*p2 = &c;   /* 4 */ 
*p1 = 'X';   /* 5 */ 

を、我々はconst char **char **を割り当てます。 (コンパイラは文句を言うべきです。)4行目でconst char *const char *を割り当てます。これは明らかに合法です。 5行目では、char *が指摘するものを修正します。これは合法的であると考えられています。しかし、p1はcを指して終わり、constです。これは、p2が本当にp1だったので、第4行目にあります。これは、行3で設定されました。これは、許可されないフォームの割り当てです。これは、行3が許可されていない理由です。

char **const char **に割り当てる(3行目と元の質問と同様)ことはすぐには危険ではありません。しかし、それはp2の約束(最終的に指摘された価値が変更されないこと)が保たれないという状況を設定します。

(C++を使用すると、警告を発生させることなく割り当てのより多くの種類を作ってみようconst -qualifiedポインタを割り当てるためのより複雑なルールを持っているが、それでもconst値を変更するための不注意の試みから保護します。C++はまだconst char **char **を割り当てることができませんが、それはあなたが* char **const char * constに割り当てることで逃さない。)Cで

、あなたが割り当てたり、間接の最初のレベル以外での修飾子ミスマッチを有するポインタを渡す必要がある場合は、明示的なキャストを使用する必要があります。 (この場合は(const char **))、いつものように、そのようなキャストの必要性は、より深いキャストが実際に修正しない問題。

参考資料:ISO Sec。 6.1.2.6、Sec。 6.3.16.1、Sec。 6.5.3 H & S Sec。 7.9.1これはあなたのために働くかどう頁221-2

+0

それは、涼しい – Andomar

0

。問題は、f()の宣言のdouble constにあります。警告と

コード:これは警告なしでコンパイル

struct_type ** v; 
v = (struct_type **)malloc(10 * sizeof(struct_type *));  
f(v); 

const struct_type *const* v; 
v = (const struct_type **)malloc(10 * sizeof(struct_type *)); 
f(v); 
-1

fは、入力としてポインタの配列(CONST struct_type * [])を得ることを期待します。 struct(const struct_type **)のポインタへのポインタを渡します。

行うための最善のことは、、IMOへのfの署名を変更することです:あなたは関数の引数として配列を渡す必要がないのはなぜ

void f(const struct_type *const* data); 

+0

そのように宣言されています:)(データの静的宣言の場合は簡単です) – elmarco

+0

Cでは、 "void ** myvar"と "void * myvar []"は同じものです。 – Andomar

+0

申し訳ありませんが、これは本当に質問への適切な答えではありません:)答えをソートするための-1 – elmarco

0

を参照してください:。

f(struct_type *data); 

void test(unsigned n) 
{ 
    struct_type *v = malloc(n * sizeof(struct_type *)); 
    f(v); 
} 

私はあなたが得る方法を教えてください。

+0

残念なことに、私は構造体を埋めるときにそれを変更する必要があるので、助けてくれません。 – elmarco

+0

構造体を塗りつぶすときでもそれを変更できます。最近私は非常によく似た問題を抱えていましたが、私のコードは次のようになりました: void clearScrorer(SCORER * scorerArray){ \t scorerArray-> name = NULL; \t scorerArray-> score = -1; } これは問題なく動作しました。 f(v)を実行することによってvへの参照を渡すことを覚えておいてください。そうすれば、関数fの中でvを修正すると、他の場所でも同様に修正されます。 – Artur

関連する問題