最新のコンパイラーは、を見つけたときにコードを最適化できますconst
。ただし、C標準ライブラリが非ポインタ引数に使用するのを見たことがありません。const
たとえばmemcmp()
、この例です。2つconst void *
の引数がありますが、3番目の引数はsize_t
です。
標準ライブラリ(および他のライブラリ)がこのように設計されているのはなぜですか?なぜ私はconst size_t
またはconst int
現代のコードで見ないのですか?
最新のコンパイラーは、を見つけたときにコードを最適化できますconst
。ただし、C標準ライブラリが非ポインタ引数に使用するのを見たことがありません。const
たとえばmemcmp()
、この例です。2つconst void *
の引数がありますが、3番目の引数はsize_t
です。
標準ライブラリ(および他のライブラリ)がこのように設計されているのはなぜですか?なぜ私はconst size_t
またはconst int
現代のコードで見ないのですか?
Cは値による呼び出しを使用します。コンパイラが関数の引数を1ビットとしてマークするのに役立ちません(の引数はconst
どれもそうではないことに注意してください。ポインタの引数も宣言できます。また、次のように指定することもできます:。しかし、そうではありません)。memcmp()
const
const
int memcmp(const void * const s1, const void * const s2, size_t const n);
コンパイラが関数の引数をマークするのに役立たない理由const
は、関数の引数は、関数の観点からはローカル変数にすぎないためです。関数がそのアドレスを受け取らない限り、コンパイラーは変数が変更されていないことを非常に簡単に確認できます。
対照的に、のプロトタイプ( )のconst
一部である修飾子は、そのコントラクトの一部です。これらは、関数が指定されたデータを変更しないことを表します。関数が引数を変更するかどうかを呼び出し元が気にしないため、修飾子が引数自体にこのように使用されることはありません。引数は単なるコピーです(Cは値による呼び出しを使用するため)。memcmp()
const void *s1
const
それらconst
は異なることを意味します。の
int memcmp ( const void * ptr1, const void * ptr2, size_t num );
const void * ptr1
これは、定数データを指しているものとしてmemcmp
扱われ、それを変更しないことを意味します。同様に。したがって、呼び出し元は、格納されている値が変更されないことを認識しており、それに応じて最適化できます。次のような関数呼び出しでptr1
const 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 );
単純なデータ型(ポインターや整数など)の場合、この方法で最適化を行うことはほとんどできません。この関数(およびその他)の元の指定子は、偶然の状況で実装が変数を変更するのを妨げる理由がないようです。
これの主な理由は、ライブラリの一貫性です。size_t
引数をaに変更const size_t
するには、サイズを変更するライブラリが書き換えられる必要があります。ライブラリのすべての実装が同じアルゴリズムを使用する必要があるわけではありません。これが、既存のライブラリ関数が適応されていない主な理由です。
新しいライブラリ関数はconst
、特定のマシン依存の実装が変更可能な引数を使用できるように、非引数を使用して意図的に作成されることがよくあります。
たとえば、Intel C ++コンパイラバージョンのは、実行中に引数をmemcmp
実際にカウントダウンします。length
他のいくつかの実装はそうしないかもしれません。