10
void * bsearch ( const void * key,
                 const void * base,
                 size_t num,
                 size_t size,
                 int ( * comparator ) ( const void *, const void * ) );

を渡すと、結果も返されconst void * baseませんか?bsearchconst void *

4

3 に答える 3

8

あなたが何かを検索するとき、それはあなたがそれを見つけた後にあなたがそれを修正することができるという有効な要求です。検索機能でそれができない場合は、制限が厳しすぎるでしょう。もちろん、そのような変更はその後の検索を壊す可能性がありますが、それは別の問題です。

パラメータは、bsearch自体がそれらを変更しないという約束としてconstであり、これは合理的です。

于 2011-10-29T10:41:45.197 に答える
3

修飾子を指す型に追加することは暗黙的な変換ですが、修飾子を削除するには明示的なキャストが必要です。

のプロトタイプはbsearch()、明示的なキャストなしで次の使用法の両方を許可する方法で書かれています。

int needle = 0xdeadbeef;

int foo[42] = { ... };
int *p = bsearch(&needle, foo, 42, sizeof *foo, cmpi);

const int bar[42] = { ... };
const int *q = bsearch(&needle, bar, 42, sizeof *bar, cmpi);

ただし、これは、bsearch()他の多くの libc 関数と同様に、警告なしで const 修飾を削除するために使用できることを意味します。

int *q = bsearch(&needle, bar, 42, sizeof *bar, cmpi);

これは完全に合法です。未定義の動作は、実際qに modifiy を使用した場合にのみ発生しますbar

また、ポインター パラメーターの const 修飾は、キャストなしで受け入れられる引数にのみ影響を与えますが、関数がポイント先の object を変更しないことを保証するものではないことにも注意してください。これは、事実上すべての既存のコードが従う規則にすぎませんが、言語のセマンティクスによって強制されるわけではありません。

特に、コンパイラはこの情報を呼び出しコードの最適化に使用することはできません。コンパイラは関数本体を確認する必要があります。これは、オブジェクト自体が変更されていない場合、ポインタから const 修飾を削除して、指定されたオブジェクトを変更することが合法であるためです。宣言されてconstいます。

以前は、ポインター引数をさらに制限修飾すると不変性が強制されると思っていましたが、セクション 6.7.3.1 を注意深く読み直すと、そうではないことがわかりました。制限修飾されたポインターは、ポインターが実際にオブジェクトにアクセスするために使用されている場合にのみ有効になりますが、呼び出しコードはプロトタイプだけからその仮定を行うことはできません...

于 2011-10-29T12:03:16.003 に答える
0

これは、C の型システムにおける最大かつ最も厄介な欠陥だと思います。これのもう 1 つの例はstrchr、まったく同じ問題を持つ関数です。ユーザーが渡したリソースへのポインターを返します。この関数は、const と非 const の両方の入力パラメーターに役立つ必要があります。あなたが見ているのは一種の妥協です。

私は、次のようなアクセサーにとって最も面倒だと思います。

const struct list *list_next(const struct list *x) { return x->next; }

内部使用の場合、マクロは優れた「多態的」実装です

#define LIST_NEXT(x) ((x)->next)

ただし、外部で使用する場合は、bsearch妥協するか、2 つの別個の関数list_nextと を使用する必要がありますlist_next_const

于 2011-11-12T22:33:26.100 に答える