4

最新のコンパイラーは、を見つけたときにコードを最適化できますconstただし、C標準ライブラリが非ポインタ引数に使用するのを見たことがありません。constたとえばmemcmp()、この例です。2つconst void *の引数がありますが、3番目の引数はsize_tです。

標準ライブラリ(および他のライブラリ)がこのように設計されているのはなぜですか?なぜ私はconst size_tまたはconst int現代のコードで見ないのですか?

4

3 に答える 3

7

Cは値による呼び出しを使用します。コンパイラが関数の引数を1ビットとしてマークするのに役立ちません(の引数はconstどれもそうではないことに注意してください。ポインタの引数も宣言できます。また、次のように指定することもできます:。しかし、そうではありません)。memcmp()constconstint memcmp(const void * const s1, const void * const s2, size_t const n);

コンパイラが関数の引数をマークするのに役立たない理由constは、関数の引数は、関数の観点からはローカル変数にすぎないためです。関数がそのアドレスを受け取らない限り、コンパイラーは変数が変更されていないことを非常に簡単に確認できます。

対照的に、のプロトタイプ( )のconst一部である修飾子は、そのコントラクトの一部です。これらは、関数が指定されたデータを変更しないことを表します。関数が引数を変更するかどうかを呼び出し元が気にしないため、修飾子が引数自体にこのように使用されることはありません。引数は単なるコピーです(Cは値による呼び出しを使用するため)。memcmp()const void *s1const

于 2012-10-06T16:51:09.920 に答える
5

それらconstは異なることを意味します。の

int memcmp ( const void * ptr1, const void * ptr2, size_t num );

const void * ptr1これは、定数データを指しているものとしてmemcmp扱われ、それを変更しないことを意味します。同様に。したがって、呼び出し元は、格納されている値が変更されないことを認識しており、それに応じて最適化できます。次のような関数呼び出しでptr1const void * ptr2

int result = memcmp(ptr1, ptr2, num);

変数ptr1、、、ptr2およびnumが関数にコピーされます。 memcmpそれらを調整しないことを約束するものではありません。ポインタが指すものを調整しないことを約束するだけです。実際、それが効率的であることが証明された場合、配列をステップスルーするために、コピーされた変数のいずれかをインクリメント/デクリメントする可能性があります。それらのいずれも変更しないことを約束したい場合、宣言は次のようになります。

int memcmp ( const void *const ptr1, const void *const ptr2, const size_t num );

単純なデータ型(ポインターや整数など)の場合、この方法で最適化を行うことはほとんどできません。この関数(およびその他)の元の指定子は、偶然の状況で実装が変数を変更するのを妨げる理由がないようです。

于 2012-10-06T17:00:25.397 に答える
0

これの主な理由は、ライブラリの一貫性です。size_t引数をaに変更const size_tするには、サイズを変更するライブラリが書き換えられる必要があります。ライブラリのすべての実装が同じアルゴリズムを使用する必要があるわけではありません。これが、既存のライブラリ関数が適応されていない主な理由です。

新しいライブラリ関数はconst、特定のマシン依存の実装が変更可能な引数を使用できるように、非引数を使用して意図的に作成されることがよくあります。

たとえば、Intel C ++コンパイラバージョンのは、実行中に引数をmemcmp実際にカウントダウンします。length他のいくつかの実装はそうしないかもしれません。

于 2012-10-06T16:53:40.797 に答える