演算子の優先順位 のバックアップソース(No.2)

演算子の優先順位について

迷ったら()をつける!

優先順位の表
|演算子|名称等|結合規則|
|() [] -> . ++ -- typeid 各種キャスト|関数,添字,メンバ選択,後置増分減分,型情報,○○_castの形のキャスト|→|
|++ -- ~ ! + - * & new delete sizeof ()|前置増分減分,補数,否定,ポインタ参照,アドレス取得,オブジェクト生成,オブジェクト破棄,サイズ取得,キャスト|←|
|* / % |乗算,除算,剰余|→|
|+ -|加算,減算|→|
|<< >>|左シフト,右シフト|→|
|< <= > >=|比較|→|
|== !=|等価|→|
|&|AND|→|
|^|EX-OR|→|
|&#x7c;|OR|→|
|&&|論理AND|→|
|&#x7c;&#x7c;|論理OR|→|
|?:|条件|←|
|= *= /= %= += -= <<= >>= &= &#x7c;= ^=|代入|←|
|,|カンマ|→|

結合規則 →:左から右 ←:右から左
上のものほど優先順位が高い

・優先順位とは
いくつかの演算子がひとつの文中で使用されている場合、優先順位の高いものから順に実行される
例えば*(乗法)は+(加法)より優先順位が高いため
 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*π=%f\n",1/b*a*d);
    printf("2/3*π=%f\n",a/b*d);
    printf("2/3*π=%f\n",a*d/b);
    printf("2/3*π=%f\n",d*a/b);

さて、上記のプログラムを実行するとどうなるだろう
自分達が普段している計算ではすべて同じはずである。しかしプログラムではそうも行かない
上のプログラムははじめの二つが0を出力し、あとの二つが望む結果を返す
&#x2a;と/は優先順位が等しく、結合法則が左から右のためである
つまりa/b*dはまずa/bを計算し、それにdを掛ける
前述の通りa/bは整数/整数なので結果は整数。つまり0が返ってくる。それにdを掛けても0である(厳密にはdを掛けた後の0は浮動小数点型なので0.0と書いたほうが良いかもしれない)

~

・&&と&#x7c;&#x7c;
&&と&、&#x7c;&#x7c;と&#x7c;これらの違いに関して述べる
例えば次のようなプログラムを考えてみる

    //入力をひとつ取りそれが2,3,5,7のうち約数であるものをすべて表示する
    //どれも約数でなければその旨表示する
    int input;
    int ans2,ans3,ans5,ans7;
    printf("好きな整数を入力してください:");
    scanf("%d",&input);
    printf("あなたの入力した数値は");
    //余りを求めてそれが0かどうかを順次確認
    if((ans2=input%2)==0 || (ans3=input%3)==0 || (ans5=input%5)==0 || (ans7=input%7)==0){
        if(ans2==0)printf("2の倍数で");
        if(ans3==0)printf("3の倍数で");
        if(ans5==0)printf("5の倍数で");
        if(ans7==0)printf("7の倍数で");
        printf("す\n");
    }else{
        printf("2,3,5,7の倍数ではありません\n");
    }

このプログラムは意図した通りには動かない
&#x7c;&#x7c;は論理ORであるためである
式1 &#x7c;&#x7c; 式2
の形があった場合、もし式1が真であれば式2は評価されない
しなくても条件が真であることが分かっているためである
つまり上記のプログラムではinputが2の倍数ならばans3以降の計算や代入は行われない
&&についても同様で
式1 && 式2
の形があった場合、もし式1が偽であれば式2は評価されない
&#x7c;や&はビットごとの演算なので
式1 &#x7c; 式2 や 式1 & 式2
の形でも式1も式2も必ず実行される
上記のプログラムも&#x7c;&#x7c;を&#x7c;に変えれば正しく動く
では&#x7c;&#x7c;や&&より&#x7c;や&を使った方がよいのだろうか?
無論そんなことはなく一般には&#x7c;&#x7c;や&&を使った方がよいだろう
評価をしないのはしなくても結果が分かっているからである
そのほうが速いのは言うまでもない


なお、&#x7c;&#x7c;や&&は比較や等号よりは優先順位が低いが、代入よりは高いので注意
というか代入の優先順位がかなり低い
a = b > c
はb>cの結果をaに代入しようとするし
a/=2 || b/=2
これはコンパイルすら通らない
a /= (2||b) /= 2
こう解釈されるためである