Cの絶対値関数がconst入力を受け入れないのはなぜですか?


23

Cでは、絶対値関数(floatを受け入れる)のプロトタイプは次のとおりです。

 float fabsf( float );

このプロトタイプが次のように定数値を受け入れないのはなぜですか。

 float fabsf( float const );

fabsfは入力の値を変更しませんか?

入力を受け入れてfabsfを呼び出す関数がある場合、入力をconstとして指定しないように強制されますか?

この状況でconstの正確さを処理する適切な方法は何ですか?


26
constここでは冗長ですが、何が起こっているのですか?
MM

1
@MM関数内の入力の値を変更しようとすると、コンパイル時エラーが発生するはずです。これは間違っていますか?
user24205

16
関数内のパラメーターはローカルコピーであるため、追加してconstもまったく意味がありません。
ランディン

1
fabsfは入力の値を変更しませんか?」どのようにしてわかりますか?パラメータは値で渡されます。
David Schwartz

次のコードは、法律上のCです:float const x = -1.0; float y = fabsf(x);私には思えるようfabsf ない constの入力を受け付けます。「float値渡しはできるが、は渡せない」と言う方法はありませんconst float。(そして、回答でわかるように、Cは関数への入力がであることを要求する方法を提供しませんfloat const。)
David K

回答:


14

編集する

MMがコメントしたように、プロトタイプのパラメーターでconstは無視されます。元の回答の編集されたソース(以下を参照)はこれを示しています。

float correct(float const value);

float erroneous(float const value);

float changer(float value);

float correct(float value) {
  return -value;
}

float erroneous(float value) {
  value = -value;
  return value;
}

float changer(float value) {
    value = -value;
    return value;
}

エラーメッセージはありません。

とにかく、私はそれが役立つことを願って元の場所に残しておきます。


元の

constパラメータでは、この可能パラメータの読み取り専用関数内を。

例えば:

float correct(float const value) {
  return -value;
}

float erroneous(float const value) {
  value = -value;
  return value;
}

float changer(float value) {
  value = -value;
  return value;
}

このソースは、エラーメッセージなしでコンパイルされません。

関数correct()は、指定された値を読み取り、その符号を変更して、否定された値を返します。

関数erroneous()は、パラメーターへの割り当てがあることを除いて、実質的に同じように動作するようです。しかし、パラメーターがそうであるため、constこれは許可されません。

次に、関数changer()は以前と同じように機能しますが、エラーは発生しません。

呼び出しサイトを見てみましょう:

float f = 3.14159;
float g = correct(f); // or erroneous(f) or changer(f)

f引数として与えられた変数はパラメータにコピーされますvaluechanger()呼び出されても変化しません。

パラメータをある種のローカル変数として見たい場合があります。実際には、生成されたマシンコードではほとんどがこのように処理されます。


それで、なぜあなたはconst時々見ますか?ポインターがパラメーターとして定義されている場合に表示されます。

指す値を変更たくない場合は、を追加する必要がありconstます。しかし、正しい位置でそれをしてください!

void effective(int const * pointer);

void futile(int * const pointer);

void possible_but_overly_restricted(int const * const pointer);

問題はプロトタイプについてですが、プロトタイプfloat fabsf( float const );は関数の実装とは何の関係もありません(これはを繰り返す必要はありませんconst)。実際const、プロトタイプでは完全に無視されます
MM

2
constはプロトタイプに行くことなく関数定義に入ることができますか?
user24205

3
@ user24205はい、可能です
Daniel Jour

33

Cは値渡しを使用します。関数のパラメーターの値は、指定した引数のコピーです。

constとnon-const floatの両方をコピーしても問題ありません。結果はnon-const floatです。

これは割り当てに似ています。

const float f = 5.5f;
float g = f;   // OK

実際、この言語では、式の値をにすることはできませんconst。つまり、変数から値を読み取ったconst場合、変数がそうであったとしても、その値はありません。


8

C言語の用途は、値のセマンティクスを通過するので任意のそれは内部的に変更することができているときに、それに渡すという議論は、直接お渡し値には影響を与えません。

これは、発信者の観点から見るfloat fabsf( float );float fabsf( const float );同じです。したがって、パラメータを作成しても意味がありませんconst

それはどこにありません使用にメイクセンスをconstあなたが渡すパラメータは、例えば、ポインタの場合です:

void print_string(char *str)

この関数は、その名前が示唆するものにもかかわらず、指定されたポインターを逆参照し、それが指すものを変更することstr[0] = 'x'ができます。この関数が次のように定義されている場合:

void print_string(const char *str)

呼び出し元は、関数がstrポイント先の変更を実行できないことが保証されます。


「呼び出し元は、関数が変更を実行できないことが保証されています...」は正しくありません。関数はデータのアドレスを知っているので、たとえば次のように変更できます((char*)str)[0] = 'f'const ... *引数リストの中には、したがって、唯一の「意思の宣言」です。
oromoiluig

5

言語弁護士の視点を追加するには:

2つの関数型が互換性を持つためには、どちらも互換性のある戻り型を指定する必要があります。さらに、パラメータタイプリストは、両方が存在する場合、パラメータの数と省略記号のターミネータの使用において一致します。対応するパラメータには互換性のあるタイプが必要です。[..]型の互換性と複合型の決定において、[..] 修飾された型で宣言されたパラメーターは、宣言された型の非修飾バージョンを持つものと見なされますます。

N1570 6.7.6.3/15

つまり、これら2つは互換性があります。

void foo(int const);
void foo(int);

したがって、プロトタイプを記述してもしなくてもconst(つまり、意味がない;タイプ/読み取りが少なくなる)const、関数内の(コピーされた-値による呼び出し!)パラメーターを誤って変更したくない場合は、関数定義に追加できます。体。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.