2011-01-13 12 views
6

私はGNU科学ライブラリのソースコードを研究してきたと私は宣言の次の型を見続ける:C99のconstが値渡し

double cblas_ddot (const int N, const double * x, const int incx, const double * y, const int incy) 

C99では、任意の(optimizational)利点があります値渡しの引数を宣言する(上記の例ではNまたはincyconst?とにかく彼らが値段で渡されているのでコピーがありますか?

Thx! コルネル

答えて

11

おそらく、呼び出し元のメリットはありませんが、呼び出し先のメリットはありません。関数のパラメータを宣言するconstは、他のローカル変数constを宣言するのと同じ効果があります。これは、変更しようとするたびに(関数のプログラマとして)自分自身にエラーを課します。

スマートではない実装では、このような宣言は、関数がインライン化されていると、決定に影響を与える可能性があります。しかし、私は今、コンパイラは、関数の定義から直接推論するものについて、このような決定を下すと思います。

これは、実装のこの仕様がインターフェイスで表現されていることは、言語の制限として確かに見ることができます。

3

はい。オプション "const"は通常、この関数に渡されるものが変更されないことを示すために使用されます。コンパイルには違いはありません。それでも価値は引き継がれます。

3

他の人が述べたように、関数はこのように宣言されているため、関数のスコープ内でその変数は変更できないため、コンパイラは警告を出す必要があります。

なぜそうしたいのかというと、ポインタを渡すことで何ができるかを考えてみましょう。つまり、渡したポインタを間接参照し、ポインタが指すデータの値を編集できます。 constを使うと、呼び出し元が変更していないと思われる値を誤って編集しないようにすることができます。

例では、これを考慮してください。これは7+11=17を出してくれる

#include <stdio.h> 

void add(int* result, const int* x, int* y) 
{ 
    *result = *x + *y; 
    (*y)++; /* <-- the caller won't expect this! */ 

} 

int main(int argc, char** argv) 
{ 
    int a = 7; 
    int b = 10; 
    int c = 0; 

    add(&c, &a, &b); 

    printf("%d + %d = %d\n", a, b, c); 
    return 0; 
} 

。さて、これは些細な、非深刻なケースですが、あなたがy変数に対してのconstを固執した場合、物事のすべての種類が...私たちは重要なものに頼ることとなりました

が起こるかもしれない、あなたが取得する必要があります。

constexample.c: In function ‘add’: constexample.c:7:5: error: increment of read-only location ‘*y’

編集、さらに明確化のために:

一つの良い理由は、非ポインタ変数のconstタイプを宣言するもののサイズ、または配列の最大値を保持する任意の変数を表す変数のためのものです。以下を検討してください:

int editstring(char* result, ..., const char* source, const size_t source_len); 

今、自分で言うと、source_lenは編集しません。さて、あなたのアルゴリズムであなたが何らかの理由で何とか言ってみましょう。あなたの変更によってsource_lenの値が増えた場合、割り当てられた範囲を超えてメモリにアクセスする危険性があります。constを設定すると、その値を変更しようとするとコンパイラエラーが発生します。

constはコンパイラに「これを編集しないことを約束します」と言っていることを二重下線で指摘しておきます。 のメモリがの読み取り専用であることを保証するものではありませんが、エラーをトラップするような意図をマークする方法です。変更する必要がない場合は、constとして宣言します。

あなたが質問したので、2つのバージョンで生成されたアセンブリは同じです。

+2

あなたの例では、パラメータ 'const'を宣言するのではなく、パラメータが指すデータを宣言します。 OPのために要求されたポインタについては、 'int * const result'のようなものになります。また、私が正しく覚えていれば、 '* y ++'は最初にポインタをインクリメントして逆参照します。発信者を妨害する可能性のあるものはありません。 –

+0

私の誤りは '(* y)++;'だったはずですが、パラメータの宣言がポインタに影響するとは決して言いませんでした - 実際、私の例の*ポイント*は、ソースメモリ。私は、標準変数constの有用性についての余分なセクションを追加しました。 –