■動作環境 :WindowsXP
■開発環境 :Visual C++6.0
お世話になります。
const指定された変数には値を代入できなくなると理解していたのですが、
プログラムを書いていたら代入できてしまったので理由が解らず質問します。
(普通constを使用する場合は以下のように使い値は変更できないと思っています。
const char *send_buffer = Hello, WinSock World!;)
下記のプログラムに書いてあるように
1.引数で受け取った物を const char *send_bufferにセットしてます。
const char *send_bufferに3回も値をセットしているのに
正常に処理が行われる理由が不明です。
2. const をつけずに char *send_bufferとすると以下のように怒られます。
(error C2679: 二項演算子 '=' : 型 'class CString' の右オペランドを扱う演算子
は定義されていません。(または変換できません)(新しい動作; ヘルプを参照))
この理由はおそらくchar型とCString型で違うからだと思います。
3.1と2をふまえてconstをつけるとコンパイルが通り、処理が正常に動く理由が
解りません。
よろしくお願い致します。
bool CClientSend::SocketStart(CString Company, CString SName, CString FName)
{
// 変数の宣言
const char *send_buffer;
// const char *send_bufferにアドレスをセット
for(int conter = 0; conter < 3; conter++){
switch(conter){
case 0:
send_buffer = Company;
break;
case 1:
send_buffer = SName;
break;
case 2:
send_buffer = FName;
break;
}
}
retrun true;
}
const がどこについているかが問題
const int c=1; // この const は c に憑く
c=2; // Error
const char * p=0; // この const は char に憑く
char buf[10];
p=buf; // OK : p は const ではない
*p='x'; // Error : *p が const
const char * p; と
char * const q; の違いはわかる?
わかるようなら const char * const r; って何か説明してみて
tetrapodさんありがとうございます。
>const char * p; と
>char * const q; の違いはわかる?
なんですが、下記のHPを参照して調べた結果
http://okuyama.mt.tama.hosei.ac.jp/unix/C/slide87-1.html
const char * pは受け取った配列の数(要素)を変更できなようにする。
char * const qはq自体が定数になりqの値を変更できなくなる。
でしょうか?
>const char * const r;
は型がconst char型要素の変更が不可でrがconstになりrの値が定数になる?
まだあやふやな理解です。
一般的に、const は型の前に書くことが多いようです。
例えば、
const int i = 0;
のように。この場合、「変更不可能な整数型」ですね。
これがポインタには通用しません。
const int * pi = &i;
の const は、あくまで int に作用するものであり、int * には作用しません。すなわ
ち、「『変更不可能な整数型』へのポインタ」になります。
俺が推奨したいのは、「後const」です。
例えば、
const int i = 0;
ではなく
int const i = 0;
と書きます(この2つのコードの意味は全く同じです)。
そして、「const は、その直前の型にかかる」と覚えます。
int const i = 0;
の場合、const は直前の int にかかりますので、「変更不可能な整数型」になります。
ここまでは、ただ書く位置を変えただけです。
これがポインタになると…
int const * pi = &i;
この場合、const は依然として、直前の int に作用しますから、「『変更不可能な整数
型』へのポインタ」になります。
int * const pi = &i;
この場合、const は直前の int * に作用しますので、「変更不可能な『整数型へのポイ
ンタ』」になります。
int const * const pi = &i;
これはその複合版。まず左の const が int にかかり、次に右の const が、そこから左
全体にかかりますから、「変更不可能な整数型への、変更不可能なポインタ」になりま
す。
シャノンさんありがとうございます。
モヤモヤがとれました。
今後ともよろしくお願い致します。
解決後にアレだが、俺の読み方とシャノン氏の読み方は違うので
こーいう読み方もある、という例を
俺の読み方は「 const は直後のブツに1回だけかかる」という方式
int const c=0; // const c と読む
int * const p=0; // const p と読む、つまり p が const で *p は const でない
int const * q=0; // const *q と読む、つまり *q が const で q は const でない
int const * const r=0;
// 後者の const を先に const r と読む
// もう後者の const は消化済みなので意識の中から削除し
// 前者の const を const *r と読む
つまり r 自体も const でありかつ *r も const と読む
俺の読み方もシャノン氏の読み方も「結合優先度」の理解なしでは読めないのは同じ
ちなみに int * x; と書いたときの読み方なんだけど
俺は *x と書いたら int になる (だから x は int へのポインタ) と教わったね
int* な x と読んでもいいけど、これは型が複雑なときに誤読が生じるかもしれない
> 俺の読み方は「 const は直後のブツに1回だけかかる」という方式
なるほど。
> int const c=0; // const c と読む
> int * const p=0; // const p と読む、つまり p が const で *p は const でない
const が型ではなくて変数名にかかるわけですか。
> int const * q=0; // const *q と読む、つまり *q が const で q は const でない
これは一瞬「あれ?」って思ったけど、参照外ししたものが const になると。
よく考えられてるなぁ。
> 俺は *x と書いたら int になる (だから x は int へのポインタ) と教わったね
これに基づく読み方ですね。
どちらにせよ、一般的に流通している「const int」方式は紛らわしいだけでしかないん
だなぁ。
#ポインタを使わずに参照だけで生きていくなら、前const の方が直感的かもしれませ
んが。
> これは型が複雑なときに誤読が生じるかもしれない
C/C++ の型ですんなり読めるのはこの程度が限度かと。
複雑なのは読めませんw
ちょいと脱線して型の読み方になってしまいますが。
> ちなみに int * x; と書いたときの読み方なんだけど
> 俺は *x と書いたら int になる (だから x は int へのポインタ) と教わったね
これ、私も似たような読み方をしています。
「宣言時の形から、実際に式中で使われる形を差っ引いたものがその式(部分式)の型」という読み方です。
int volatile *const p;
なら
「p」は「int volatile *const」だし、「*p」は(*とpの間にあるconstは潰れて)「int
volatile」。
もうちょっとややこしく
double *const (*func(int x, int y))[10];
という宣言があったとしても、
「func(10, 20)」は「double *const (*)[10]」、
「*func(10, 20)」は「double *const [10]」、
「(*func(10, 20))[1]」なら「double *const」と、機械的に型が分かります。
実際に、「funcはdoubleへのポインタ10個からなる(変更不能な配列)へのポインタを返す関数」などと
読み下さなくても、どういった形で使えばどういった型として扱えるのかが分かるのが強み。
funcの例だと、最終的にdouble型を得たいなら、「*(*func(10, 20))[1]」のような書き方を
すればいいし、constが残ってしまうため、「変更可能な(doubleへのポインタ)」を得るのは不可能、
といったことも分かります。
まあ、普通は宣言時にtypedefを挟んだり、利用時に別変数に代入したりで、直接ここまでややこしい
書き方をすることはまずありませんが。
欠点は関数へのポインタがからむと必ずしも適用できないこと。
この方法では、int (*func2)(void); と宣言して、func2()と書いたり、(**************func2)
()と
書いた場合の型がintになるとは分かりません。
これまた後者の書き方なんてまずやらないけど。