23

標準Cライブラリは機能strtofstrtod、次のシグネチャを持っています。

float strtof(const char *str, char **endptr);
double strtod(const char *str, char **endptr); 

それらはそれぞれ、入力文字列strを3つの部分に分解します。

  1. 最初の、おそらく空の空白のシーケンス
  2. 浮動小数点値を表す文字の「サブジェクトシーケンス」
  3. 認識されない(変換に影響を与えない)文字の「トレーリングシーケンス」。

でない場合endptrNULL*endptr変換の一部であった最後の文字の直後の文字へのポインターに設定されます(つまり、末尾のシーケンスの開始)。

私は疑問に思っています:endptrそれでは、なぜconst charポインタへのポインタなのですか?文字列(入力文字列)*endptrへのポインタではありませんか?const charstr

4

2 に答える 2

11

その理由は単に使いやすさです。char *は自動的にに変換できますがconst char *、自動的にに変換char **することはできませんconst char **。また、呼び出し元の関数が使用するポインターの実際のタイプ(アドレスが渡される)は、よりもはるかに高い可能性がchar *ありconst char *ます。この自動変換が不可能な理由は、constいくつかのステップで資格を削除するために使用できる非自明な方法があり、各ステップ自体が完全に有効で正しいように見えるためです。スティーブジェソップはコメントで例を提供しました:

に自動的に変換できる場合char**const char**

char *p;
char **pp = &p;
const char** cp = pp;
*cp = (const char*) "hello";
*p = 'j';.

const-safetyの場合、これらの行の1つは違法である必要があり、他の行はすべて完全に正常な操作であるため、次のようにする必要があります。cp = pp;

より良いアプローチは、の代わりにこれらの関数を定義することvoid *でしchar **た。char **とは両方ともconst char **自動的にに変換できますvoid *(打たれたテキストは実際には非常に悪い考えでした。型チェックを妨げるだけでなく、Cは実際に型のオブジェクトchar *とエイリアスを禁止します。)あるいは、これらの関数は、のオフセットを格納するためのまたは引数const char *を取ることができます。それへのポインタではなく、終了します。とにかく、これは多くの場合より便利です。ptrdiff_t *size_t *

後者のアプローチが気に入った場合は、標準ライブラリ関数の周りにそのようなラッパーを記述してラッパーを呼び出し、残りのコードをconstクリーンでキャストフリーに保つことができます。

于 2010-10-06T15:41:35.067 に答える
5

使いやすさ。入力引数は変更されないため、引数strはとしてマークされます。constもしそうならendptr、それは彼が出力から参照されるデータを変更してはならないことを呼び出し元constに指示しますが、多くの場合、呼び出し元はまさにそれをしたいと思っています。たとえば、floatを取り出した後、文字列をnullで終了したい場合があります。endptr

float StrToFAndTerminate(char *Text) {
    float Num;

    Num = strtof(Text, &Text);
    *Text = '\0';
    return Num;
}

状況によっては、やりたいことは完全に合理的です。endptrタイプがの場合は機能しませんconst char **

理想的にendptrは、const-nessが実際の入力const-nessと一致する必要がありますstrが、Cはその構文を通じてこれを示す方法を提供しません。( Anders Hejlsbergは、C#から除外された理由を説明するときにこれについて話します。)const

于 2010-10-06T15:58:19.250 に答える