複雑なポインタ宣言を読み取るには、 右左規則 があります。
しかし、このルールはconst
修飾子の読み方については触れていません。
たとえば、単純なポインタ宣言では、const
はいくつかの方法で適用できます。
_char *buffer; // non-const pointer to non-const memory
const char *buffer; // non-const pointer to const memory
char const *buffer; // equivalent to previous declartion
char * const buffer = {0}; // const pointer to non-const memory
char * buffer const = {0}; // error
const char * const buffer = {0}; // const pointer to const memory
_
次に、ポインタ宣言のポインタでのconst
の使用についてはどうですか?
_char **x; // no const;
const char **x;
char * const *x;
char * * const x;
const char * const * x;
const char * * const x;
const char * const * const x;
_
そして、それらの宣言を読むための簡単なルールは何ですか?どの宣言が意味がありますか?
時計回り/スパイラルルール は適用可能ですか?
メソッド _ASTUnit::LoadFromCommandLine
_ は_const char **
_を使用してコマンドライン引数を提供します(llvm clangソース内)。
getopt()
の引数ベクトルパラメータは次のように宣言されます。
_int getopt(int argc, char * const argv[], const char *optstring);
_
この場合、_char * const argv[]
_は_char * const * argv
_と同等です。
どちらの関数も同じ概念(引数を提供するための文字列へのポインターのベクトル)を使用しており、宣言が異なるため、明白な質問は次のとおりです。なぜ違うのですか?もう1つより意味がありますか?
意図は次のとおりです。const
修飾子は、関数がこのベクトルの文字列を操作せず、ベクトルの構造を変更しないことを指定する必要があります。
const
修飾子は取るに足らないものです。前に何もない場合を除いて、前にあるものを変更します。そう:
_char const* buffer; // const modifies char
char* const buffer; // const modifies *
_
、など。一般的に、const
の前に何もないフォームは避けるのが最善ですが、実際にはそれらが表示されるため、const
の前に型がない場合は、論理的にその後ろに移動する必要があることを覚えておく必要があります。最初のタイプ。そう:
_const char** buffer;
_
実際には:
_char const** buffer;
_
、つまりconst charへのポインタへのポインタ。
最後に、関数宣言では、_[]
_ afterは_*
_ beforeとして読み取ります。 (この場合も、この誤解を招くような表記は避けた方がいいでしょうが、それを目にすることになるので、対処する必要があります。)
_char * const argv[], // As function argument
_
です:
_char *const * argv,
_
charへのconstポインタへのポインタ。
(質問の他の側面に集中しようとする)
const宣言の経験則 は、右から左に読み取ることであり、const
は次のトークンを変更します。例外:宣言の始めにconst
は前のトークンを変更します。
この例外の背後にある根拠 -基本的な宣言の場合_const char c
_は_char const c
_よりも自然な人を探しますが、_const char c
_の前駆形であると報告されています最終的なconstルールよりも古い。
_int getopt(int argc, char * const argv[], const char *optstring);
_
または
_int getopt(int argc, char * const * argv, const char *optstring);
_
つまり、argv
は、非const文字列へのポインターのconstベクトルへのポインターです。
しかし、次の宣言が期待されます。
_int getopt(int argc, char const * const * argv, const char *optstring);
_
(const文字列へのconstベクトルへのポインター)
getopt()
は、argvを介して参照される文字列を変更することを想定していないためです。
少なくとも_char **
_(main()
で使用される)は自動的に_char * const * argv
_に変換されます。
_ASTUnit::LoadFromCommandLine(..., const char **argv, ...);
_
つまり、argv
は、const文字列へのポインターの非const配列へのポインターです。
再び、上記と同じ理由で_const char * const *argv
_を期待します。
ただし、_char **
_ 変換しない から_const char **
_に変換されるため、これはより顕著になります。
_int main(int argc, char **argv) {
const char **x = argv; // Compile error!
return 0;
}
_
コンパイルエラーが発生します。
_int main(int argc, char **argv) {
char * const *x = argv;
return 0;
}
_
そして
_int main(int argc, char **argv) {
const char * const *x = argv;
return 0;
}
_
しない。