演算子の優先順位

2016年06月07日 (火) 15時20分11秒
このエントリーをはてなブックマークに追加

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
こう解釈されるためである