C ++およびCの関数パラメーターとしての「const int」と「int const」


116

考慮してください:

int testfunc1 (const int a)
{
  return a;
}

int testfunc2 (int const a)
{
  return a;
}

これら2つの機能はすべての面で同じですか、それとも違いがありますか?

C言語の答えに興味がありますが、C ++言語に何か面白いものがあったら知りたいです。


Cにconstキーワードはありますか?以前はありませんでしたが、C 99標準にはあまり慣れていません。
Onorio Catenacci

8
する必要はありません。C90で十分です。オリジナルのK&R Cにはありませんでした。
Mark Ba​​ker、

3
C89とANSIのキーワードです。それがカーニンガムとリッチーの時代のキーワードだったかどうかはわかりません。
Nils Pipenbrinck 2008年

7
このサイトは「C意味不明
Motti

5
私は「Cの意味不明なものから英語の意味不明なもの」と言いますが、それでも素敵です:)
コス

回答:


175

const TT const同一です。ポインタ型を使用すると、より複雑になります。

  1. const char* 定数へのポインタです char
  2. char const* 定数へのポインタです char
  3. char* const (可変)への定数ポインタです char

つまり、(1)と(2)は同じです。(指示先ではなく)ポインタを作成する唯一の方法はconst、接尾辞-を使用することですconst

これが、多くの人々が常にconst型の右側に置くことを好む理由です(「East const」スタイル):型との相対的な位置を一貫して覚えやすくします(また、初心者に教えるのが簡単になるように思われます) )。


2
与えられたCにはconstがあります:static const char foo [] = "foo"; fooを変更しない方がよいでしょう。
James Antill、

4
K&R Cにはconstがありませんでした。C90(およびC99)にはあります。C ++と比較すると少し制限されていますが、便利です。
Mark Ba​​ker、

これはリファレンスにも当てはまりますか?
ケン

1
@ケンはい、同じです。
Konrad Rudolph

1
@étale-cohomology良い点を追加。ずっとそこにあったはずです。
Konrad Rudolph

339

トリックは、宣言を逆方向(右から左)に読むことです。

const int a = 1; // read as "a is an integer which is constant"
int const a = 1; // read as "a is a constant integer"

どちらも同じものです。したがって:

a = 2; // Can't do because a is constant

特に、次のようなより複雑な宣言を処理する場合は、逆読みのトリックが役立ちます。

const char *s;      // read as "s is a pointer to a char that is constant"
char c;
char *const t = &c; // read as "t is a constant pointer to a char"

*s = 'A'; // Can't do because the char is constant
s++;      // Can do because the pointer isn't constant
*t = 'A'; // Can do because the char isn't constant
t++;      // Can't do because the pointer is constant

5
「char const * u」はどうですか?これは「定数文字へのポインター」または「文字への定数ポインター」を読みますか?あいまいなようです。標準は前者を述べていますが、これを見つけるには、優先順位と結合規則を考慮する必要があります。
Panayiotis Karabassis

5
@PanayiotisKarabassisすべての場所を入れ替えることなく、形容詞の連鎖として扱う必要があります。char const *、左から右に読むと、「pointer、const、char」です。これはconst charへのポインタです。「定数のポインター」と言うと、「定数」の形容詞はポインターの上にあります。したがって、その場合、形容詞のリストは「const、pointer、char」である必要があります。しかし、あなたの言う通り、このトリックにはあいまいさがあります。これは実際には「トリック」であり、決定的な「ルール」ではありません。
Ates Goral

5
配列、関数、ポインター、関数ポインターのワイルドな組み合わせを宣言すると、逆方向読み取りが機能しなくなります(悲しいことに)。ただし、これらの乱雑な宣言はらせん状に読むことができます。他の人たちは彼らにとても不満を抱いて、Goを発明しました。
マーティンJH

@Martin JH:typedefを使って分割することはできませんか?および/または間接参照を排除するために参照を使用していますか?
Peter Mortensen

14

違いはありません。どちらも「a」は変更できない整数であることを宣言しています。

違いが現れるのは、ポインタを使用するときです。

これらの両方:

const int *a
int const *a

「a」を変更しない整数へのポインターとして宣言します。「a」は割り当て可能ですが、「* a」は割り当てできません。

int * const a

「a」を整数への定数ポインタとして宣言します。「* a」は割り当てることができますが、「a」は割り当てることができません。

const int * const a

「a」を定数整数への定数ポインタとして宣言します。"a"も "* a"も割り当てられません。

static int one = 1;

int testfunc3 (const int *a)
{
  *a = 1; /* Error */
  a = &one;
  return *a;
}

int testfunc4 (int * const a)
{
  *a = 1;
  a = &one; /* Error */
  return *a;
}

int testfunc5 (const int * const a)
{
  *a = 1;   /* Error */
  a = &one; /* Error */
  return *a;
}

最後の例は、最も単純な説明です。
1

7

Prakashは、宣言が同じであることは正しいですが、ポインターのケースのもう少しの説明が正しいかもしれません。

「const int * p」は、intへのポインターであり、そのポインターを通じてintを変更することはできません。「int * const p」は、別のintを指すように変更できないintへのポインターです。

https://isocpp.org/wiki/faq/const-correctness#const-ptr-vs-ptr-constを参照してください


アンカー( "faq-18.5。")が壊れています。どちらを参照すればよいですか( "const"と "*"の付いたものはいくつかあります)?
Peter Mortensen

@PeterMortensen:うん、リンク腐敗。ありがとう。リンクを更新しました。
フレッドラーソン

5

const intint constCのすべてのスカラー型で当てはまるように、はと同じです。一般に、constCの値による呼び出しのセマンティクスは、変数への変更は、それを囲む関数に対してローカルであることを意味するため、スカラー関数パラメーターを不要に宣言する必要はありません。


4

これは直接的な答えではなく、関連するヒントです。物事をまっすぐにするために、私は常に「const外側に置く」という対流を使用します。「外側」とは、左端または右端を意味します。そうすれば、混乱が生じることはありません。constは最も近いもの(型または*)に適用されます。例えば、



int * const foo = ...; // Pointer cannot change, pointed to value can change
const int * bar = ...; // Pointer can change, pointed to value cannot change
int * baz = ...; // Pointer can change, pointed to value can change
const int * const qux = ...; // Pointer cannot change, pointed to value cannot change

6
「constはconstに残っているものを何でもできる」というルールを使用する方がよいでしょう。たとえば、 "int * const foo"は、ポインタが "const"になるようにします。ただし、2行目に「int const * bar」と書くと、intが残されているため、intがconstになります。"int const * const * qux"は、intとポインタのどちらか一方が残されているため、intとポインタの両方をconstにします。
Mecki 2010

4

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

int getInt() const;

これは、変更thisから関数内のポインタをFoo * constしますFoo const * constこちらをご覧ください。


3
これは、まったく異なる種類のconstです。
Justin Meiners

1
なぜこれが完全に違うのですか?反対票を獲得するのに十分異なる。
Nick Westgate

1
はい、問題は「const int」と「int const」の違いについてです。あなたの答えはそれとは無関係です。
Justin Meiners

1
同じだと言った。それでも、受け入れられ、上位投票された回答には、ポインタタイプに関する追加情報も含まれています。あなたもそれらに反対票を投じましたか?
Nick Westgate


3

この場合は同じだと思いますが、順序が重要な例を次に示します。

const int* cantChangeTheData;
int* const cantChangeTheAddress;

2
確かに、しかしint const *は最初のものと同じなので、intとconstの順序は関係ありません。それは*とconstの順序だけです。
Mark Ba​​ker、
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.