概要
- コンマは演算子なんだよ~って話。
- 演算子の優先度の話。
- 実例を交えた話。
といった感じで、
コンマを演算子と認識していなかったために起こった、プログラムの意図しない挙動と調べたことを紹介。
これは、浅瀬で溺れた話です。
コンマ演算子
左被演算子を評価しその値を捨て、その後右被演算子を評価する演算子である。
コンマ演算子の値と型は右被演算子の値と型となる。C では右辺値だが、C++ では右被演算子が左辺値であれば左辺値となる。また、左被演算子の評価に対する副作用(C++では一時変数の破棄を除く)が完了した後に右被演算子が評価されることが規格上保証されている。(Wikipediaより)
演算子の優先度
結論だけ言うと、コンマ演算子は最も優先度が低いです。
詳しく知りたい方はコチラを見てください。
ここまでを解説
int a=1, b=2, i;
// 例1
i = a, b;
// 例2
i = (a, b);
例1は結果的にi = a
となります。
代入演算子の方が優先度が高いため、コンパイラ的にはi = a; b;
のようになるためです。
例2は結果的にi = b
となります。
()でくくられているため、先に演算されます。
a, b
を演算すると例によって左辺値a
が捨てられて右辺値b
が評価されます。
結果、残ったb
がi
に代入される形で、コンパイラ的にi = b;// aは捨てられた!
になります。
わかりました??実際テストコードを書いてみると動きがよくわかります。
実際に起こったこと
void Show(int a);
void Show(int a, int b);
int main()
{
bool flag = getFlag();//フラグを取得し
Show( flag ? x , y : x );//フラグに応じて、引数を変更する。
}
コードを書いた時の感覚的に、flag
が正の時は**x, y
が引数に、負の時はx
が引数**に入るイメージでした。(ここがすべての原因)
起こっていたことを説明
- 正の場合
三項演算子も立派な演算子です。flag
を評価した後、三項演算子の式1x , y
を評価しに行きます。
コンマ演算子はx
を捨てy
が残り、関数呼び出しがShow(y);
となります。 - 負の場合
三項演算子の式2だけを評価するので、関数呼び出しがShow(x);
となります。(これは普通の流れ)
どちらも**void Show(int a);
**を呼び出す結果となってしました。
コンパイル時にはエラーにならないので気づけませんでした。
環境によっては、ビルド時にwarningが出ます。
意外と簡単な話でしたね。そして、情けない話です...。
ちなみに
この実装で修正するなら
flag ? Show(x, y) : Show(x);
これですかね。
まとめ
何気なく区切りなどに使っていて、コンマ演算子をしっかり理解できていない人もいたのではないでしょうか。
普通、今回の件のような使い方はしないので、レアケースだと思います(笑)
コードとしても可読性が低いので、そもそも実装を見直すことがベターでしたね。
言語によっては若干仕様が違うこともあるそうです。小ネタにでもなれば幸いです。