前のconstまたは後のconst?


145

開始するには、おそらくそれを知っています const使用して、オブジェクトのデータまたはポインタを変更できないようにするか、またはその両方を行うことができることます。

const Object* obj; // can't change data
Object* const obj; // can't change pointer
const Object* const obj; // can't change data or pointer

ただし、次の構文も使用できます。

Object const *obj; // same as const Object* obj;

問題と思われるのは、アスタリスクのどちら側に置くかだけです。 constキーワードを入力。個人的にconstは、タイプの左側に置いて、データが変更可能ではないことを指定することを好みます。左から右への考え方ではデータが読みやすいため、どの構文が最初に来るのですか?

さらに重要なのは、なぜ指定する2つの正しい方法があるのか constデータ、また、どのような状況で、どちらか一方を好むか、どちらか一方が必要な場合にどちらが必要かということです。

編集:

ですから、私が生まれるずっと前にコンパイラが物事を解釈する方法の標準が起草されたとき、これは恣意的な決定だったようです。constはキーワードの左側にあるものに適用されるので(デフォルトでは?)、少なくとも宣言が変更されるときまで、他の方法でキーワードと型修飾子を適用するための「ショートカット」を追加しても害はなかったと思います*または&の解析...

これはCの場合もそうでした。


9
マクロでは常に追加しconst た後、例えば、タイプ#define MAKE_CONST(T) T constの代わりに、#define MAKE_CONST(T) const TそれはとてもMAKE_CONST(int *)正確に拡大するint * const代わりにconst int *
jotik

6
「east const」と「west const」と呼ばれるこれらの2つのスタイルを見てきました。
トムアンダーソン

13
@TomAndersonですが、実際には "east const"および "const west"である必要があります。
YSC 2018年

回答:


96

constデータを指定する正しい方法が2つあるのはなぜですか。また、どのような場合に、どちらか一方を好むか、もう一方よりも必要な場合がありますか。

本質的に、 constに、アスタリスクの前の指定子内は、C文法がカーニハンとリッチーによってそのように定義されたからです。

彼らがこのように文法を定義した理由は、Cコンパイラが入力を左から右に解析し、それを消費するにつれて各トークンの処理を終了したためと考えられます。かかる*トークンはポインタ型に現在宣言の状態を変化させます。const後に遭遇*するとは、const修飾子がポインター宣言に適用されることを意味します。前にそれに遭遇*修飾子はデータに適用される手段はを指摘しました。

意味の意味は変化しないので const修飾子が型指定子の前または後にあるどちらの方法でも受け入れられます。

関数ポインターを宣言するときにも、同様のケースが発生します。

  • void * function1(void)返す関数を宣言しvoid *

  • void (* function2)(void)は、を返す関数への関数ポインタを宣言しますvoid

ここでも注目すべきは、言語構文が左から右へのパーサーをサポートしていることです。


7
カーニハン氏はこの本を共同執筆しましたが、Cのデザインには関与せず、リッチー氏だけが関与しました。
Tom Zych、2011

8
どっちがどっちなのか思い出せなかった。あなたの説明のおかげで、私はそれを覚えるのにやっとニーモテクニックを使うことができました。ありがとう!前*コンパイラのパーサは、それがポインタであるかを知らないので、それは、データ値のconstがあります。*の後は、定数ポインターに関連しています。鮮やかさ。そして最後に、なぜ私const charも同様にできるのかを説明しchar constます。
Vit Bernatik 2017年

2
なぜそれがこのように行われたのかについての推測は、私にはかなり弱い/自己矛盾しているようです。つまり、私が言語を定義してコンパイラーを作成していて、それをシンプルに保ち、「入力を左から右に解析し、トークンを消費するときに各トークンの処理を終了する」ことを望んでいた場合、const資格のあるものの後に必ず来るように要求します...まさにそのため、消費した直後に常にconstの処理を完了することができます。したがって、これはwest-constを許可するのではなく、禁止するための議論のようです。
ドンハッチ

3
「const修飾子が型指定子の前または後に現れても意味の意味は変わらないため、どちらの方法でも受け入れられます。」その循環的な推論ではないですか?問題は、意味の意味がそのように定義されている理由です。そのため、この文は何の貢献にもならないと思います。
ドンハッチ

1
@donhatch今日、優れたプログラミング言語の設計に精通していることに基づいて私たちが行う仮定に比べて、言語はかなり新しいものであったことを覚えておく必要があります。また、許容される言語か制限された言語かは、価値の判断です。たとえば、Pythonには++演算子が必要ですか?「その文」imhoは、彼らができるという理由以外に特別な理由はないということに気づかされました。多分彼らは今日別の選択をするだろうし、そうでないかもしれない。
ragerdl 2018年

75

ルールは:

constは、残っているものに適用されます。左側に何もない場合は、右側に適用されます。

constが定義されている「元の」方法であるという理由だけで、constの右側にconstを使用することを好みます。

しかし、これは非常に主観的な見方だと思います。


18
左に置く方がいいですが、右に置く方が理にかなっていると思います。通常、C ++で型を右から左に読み取りますObject const *。たとえば、constオブジェクトへのポインターです。をconst左側に置くと、constであるObjectへのポインターとして読み取られますが、これは実際にはあまりうまく流れません。
Collin Dauphinee

1
左側は他の種類のC宣言との人間スタイルの一貫性を保つための印象です(constストレージクラスではないため、コンピューターでは正しくありませんが、人々はパーサーではありません)。
geekosaur

1
@Heathルールよりもガイドラインの方が多いと思います。コンパイラーがそれをどのように解釈するかを思い出す方法としてよく耳にしました...私はそれがどのように機能するか理解しているので、背後にある思考プロセスにのみ興味がありましたそれを両方の方法でサポートする決定。
AJG85 2011年

3
@HeathHunnicuttルールは存在しますが、少し複雑です:c-faq.com/decl/spiral.anderson.html
imallett

2
@HeathHunnicutt:スパイラルルールは、最初のコメント作成者のコメント「通常、[C /] C ++の型を右から左に読む」の拡張バージョンです。私はあなたがこれに矛盾していたと思います。しかし、あなたは代わりに答え自体を参照していたのではないかと思います。
イマレット2014年

56

私は2番目の構文を好みます。これは、型宣言を右から左に読むことで、「何が」が一定であるかを追跡するのに役立ちます。

Object * const obj;        // read right-to-left:  const pointer to Object
Object const * obj;        // read right-to-left:  pointer to const Object
Object const * const obj;  // read right-to-left:  const pointer to const Object

3
丁度。「定数オブジェクトへの定数ポインタ」はObject const* const、ではなくconst const Object*です。「const」は、非常に多くの人が絶対に愛する特別な場合を除いて、左側には配置できません。(上記のヒースを参照してください。)
cdunn2001、2014年

38

宣言内のキーワードの順序は、すべてが固定されているわけではありません。「1つの真の順序」には多くの代替手段があります。このような

int long const long unsigned volatile i = 0;

それとも

volatile unsigned long long int const i = 0;

??


25
+1は、単純な変数の完全に混乱する定義です。:)
Xeo

@rubenvb-はい、残念ながらそうです。文法では、a decl-specifier-seqdecl-specifiersのシーケンスであると述べています。文法による順序はなく、各キーワードの出現回数は、いくつかのセマンティックルールによってのみ制限されます(1 constlong
Bo Persson

3
@rubenvb-はい、unsignedタイプであり、unsigned intおよびと同じint unsignedです。およびとunsigned long同じ別のタイプです。パターンがわかりますか?unsigned long intint long unsigned
Bo Persson、

2
@Bo:混乱を参照してください;)。パターンを確認するには3つ必要です。OK、ありがとう
rubenvb '19年

1
staticかつてはごちゃごちゃした単語を追加することができましたが、コンパイラーが不満を言ったのstaticは最近のことです。
Mark Lakata

8

最初のルールは、ローカルのコーディング標準で必要な形式を使用することです。その後:consttypedefが関係している場合、前に置くことで混乱が続くことはありません。例:

typedef int* IntPtr;
const IntPtr p1;   // same as int* const p1;

コーディング標準でtypedefのポインターが許可されている場合は、型の後にconstを置くように強制する必要があります。すべての場合を除いて、型に適用される場合、constはそれが適用されるものに従う必要があるため、一貫性は後のconstを支持して主張します。しかし、ローカルのコーディングガイドラインはこれらすべてに優先します。通常、この違いはさかのぼって既存のコードをすべて変更するほど重要ではありません。


このショップでは、緩やかに定義された標準にポインターのtypedefがない理由を強調していると思います。
AJG85 2011年

1
私のポリシーは、(私が一人で決めてもらうとき)の後(コヒーレンスのために)のconstを置くことである(あまり一般的でかのtypedef)のポインタへのtypedefを使用しないように:-)。ところで、string :: iteratorとstring :: const_iteratorは、おそらくあなたの決定にも考慮する必要があります。(混乱させるだけです:-)。正解はありません。)
James Kanze

ああはい、私はconst std::string::const_iteratorかなりの程度での行動も含めたかもしれません;)
AJG85 2011年

2
@JamesKanze —少し待って、ここで私を助けてください...投稿された例に混乱は見られません。const IntPtr p1「定数整数ポインタ」(つまり、「定数への定数ポインタ」)以外の意味は何でしょうか?どのようIntPtrに定義されているかを知らなくても、それをp1変更可能だと考える人はいないでしょう。そしてそれについて、なぜ誰もがそれ*p1が不変であると誤って仮定するのでしょうか?さらに、constを他の場所(たとえばIntPtr const p1)に置いても、セマンティクスはまったく変わりません。
トッドリーマン

3
@ToddLehman混乱は見られないかもしれませんが、ほとんどのC ++プログラマーは誤解し、体系的に誤解しています(間違いなくstd::vector<T>::const_iterator、のようなものによって助けられます。
James Kanze

7

左または右のどちらかが許容されるという歴史的な理由があります。Stroustrupは1983年までにC ++にconstを追加しましたが、C89 / C90まではCになりませんでした。

C ++では、常に右側でconstを使用するのに十分な理由があります。constメンバー関数は次のように宣言する必要があるため、どこでも一貫性があります。

int getInt() const;

1
...まあ、「正当な理由」はそれほど説得力がありません。なぜなら、「const」の他の可能な場所は同じことを意味しないからです。 const int& getInt(); int& const getInt();
Maestro

1
@Maestro:int const& getInt();同等のものよりも優れてconst int& getInt();いるint& const getInt();ことをお勧めしますが、それを比較すると冗長です(参照はすでにconstです)が合法であり、通常は警告が表示されます。とにかく、メンバー関数のconstは、関数のthisポインターをからFoo* constに変更しますFoo const* const
Nick Westgate

constメンバー関数の意味はまったく同じではありません。またはvoid set(int)&;関数への参照のようなものですか?
Davis Herring
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.