演算子の優先順位
C・C++における演算子の優先順位について
迷ったら()をつける!
優先順位の表
演算子 | 名称等 | 結合規則 |
:: | スコープ解決(名前空間、C++のみ) | → |
() [] -> . ++ -- typeid 各種キャスト | 関数,添字,メンバ選択,後置増分減分,型情報,○○_castの形のキャスト | → |
++ -- ~ ! + - * & new delete sizeof () | 前置増分(インクリメント)減分(デクリメント),補数,否定,ポインタ参照,アドレス取得,オブジェクト生成,オブジェクト破棄,サイズ取得,キャスト | ← |
* / % | 乗算,除算,剰余 | → |
+ - | 加算,減算 | → |
<< >> | 左シフト,右シフト | → |
< <= > >= | 比較 | → |
== != | 等価 | → |
& | AND | → |
^ | EX-OR | → |
| | OR | → |
&& | 論理AND | → |
|| | 論理OR | → |
?: | 条件(三項) | ← |
= *= /= %= += -= <<= >>= &= |= ^= | 代入 | ← |
, | カンマ | → |
結合規則 →:左から右 ←:右から左
上のものほど優先順位が高い
・優先順位とは
いくつかの演算子がひとつの文中で使用されている場合、優先順位の高いものから順に実行される
例えば*(乗法)は+(加法)より優先順位が高いため
a+b*c
はまずb*cが実行されたのちその結果とaを足す
・結合規則とは
結合規則とは多数並んでいる場合に実行される順番のこと
例えば=(代入)の結合規則は右から左であるので
a=b=c
は
a=(b=c)
と解釈される。つまりaにもbにもcが代入される
少し話がそれるが、整数(=整数型 intとかcharとか)/整数の結果は整数で返る
例えばa=2/3とすればaには0が入る
実数(=浮動小数点型 doubleとか)/整数 あるいは 整数/実数 そして当然 実数/実数 は実数が返る
ここでも結合規則について注意すべき場合がある
次の例を見てみよう(60°の弧度法表示を求めるプログラム)
int a,b; double d; a=2; b=3; d=3.14; printf("2/3*3.14=%f\n",1/b*a*d); printf("2/3*3.14=%f\n",a/b*d); printf("2/3*3.14=%f\n",a*d/b); printf("2/3*3.14=%f\n",d*a/b);
さて、上記のプログラムを実行するとどうなるだろう
自分達が普段している計算ではすべて同じはずである。しかしプログラムではそうも行かない
上のプログラムははじめの二つが0を出力し、あとの二つが望む結果を返す
*と/は優先順位が等しく、結合法則が左から右のためである
つまりa/b*dはまずa/bを計算し、それにdを掛ける
前述の通りa/bは整数/整数なので結果は整数。従って0が返ってくる。それにdを掛けても0である(厳密にはdを掛けた後の0は浮動小数点型なので0.0と書いたほうが良いかもしれない)
・&&と||
&&と&、||と|これらの違いに関して述べる
少々無理やりな例だが、次のようなプログラムを考えてみる
int input; int ans2,ans3; scanf("%d",&input); printf("The input value "); if((ans2=input%2)==0 || (ans3=input%3)==0){ printf("is a multiple of "); if(ans2==0)printf("2.\n"); if(ans3==0)printf("3.\n"); }else{ printf("is not a multiple of 2 and is not a multiple of 3.\n"); }
このプログラムは意図した通りには動かない
||は論理ORであるためである
式1 || 式2
の形があった場合、もし式1が真であれば式2は評価されない
しなくても条件が真であることが分かっているためである
つまり上記のプログラムではinputが2の倍数ならばans3の計算や代入は行われない
&&についても同様で
式1 && 式2
の形があった場合、もし式1が偽であれば式2は評価されない
|や&はビットごとの演算なので
式1 | 式2 や 式1 & 式2
の形でも式1も式2も必ず実行される
上記のプログラムも||を|に変えれば正しく動く
では||や&&より|や&を使った方がよいのだろうか?
無論そんなことはなく一般には||や&&を使った方がよいだろう
評価をしないのはしなくても結果が分かっているからである
そのほうが速いのは言うまでもない
なお、||や&&は比較や等号よりは優先順位が低いが、代入よりは高いので注意
というか代入の優先順位がかなり低い
a = b > c
はb>cの結果をaに代入しようとするし
a/=2 || b/=2
これはコンパイルすら通らない
a /= (2||b) /= 2
こう解釈されるためである