C言語のきほん|優先順位の総まとめ

迷ったらカッコ!優先順位と結合規則を“安全に使いこなす”総まとめで、条件式と計算式が読みやすくなるよ。

演算子の優先順位と結合規則は、覚え始めるとちょっと情報量が多く感じます。でも安心してね。実務でも学習でも、完璧に暗記するより「よく出るパターンを確実に読む」ほうが大事です。

この総まとめでは、

  • カッコで優先順位を明示する理由
  • 読みにくい式を読みやすくする書き換え
  • 確認問題で理解を固める
  • コンマ演算子(,)の正体と、区切りのカンマとの違い

を、セットで整理していきます。

丸括弧で優先順位を明示する

カッコは「計算順序の指定」と「読みやすさアップ」の両方に効く

たとえば、次の式は * が + より先に計算されます。

int result = 2 + 3 * 4;

でも「先に足したい」なら、丸括弧で意図を固定できます。

int result = (2 + 3) * 4;

計算の流れはこうです。

(2 + 3) = 5
5 * 4 = 20

サンプルプログラム:買い物の合計

ファイル名:6_11_1.c

#include <stdio.h>

int main(void)
{
    int snack = 2;
    int add = 3;
    int packs = 4;

    int total1 = snack + add * packs;       /* 掛け算が先 */
    int total2 = (snack + add) * packs;     /* 足し算を先にしたい */

    printf("カッコなしの計算結果: %d\n", total1);
    printf("カッコありの計算結果: %d\n", total2);
    printf("メッセージ: カッコは意図を固定する便利アイテムだよ。\n");

    return 0;
}

条件式こそカッコで読みやすくする

&& と || が混ざると、人間の目がつまずきやすい

次の式は、ルール上は && が || より優先なので、先に && が評価されます。

if (a < b && b < c || a == c) {
    /* ... */
}

動きとしては問題なくても、「ぱっと見で意図が伝わりにくい」ことがあります。
そこで、読み手に意図を伝えるためにカッコを付けます。

if ((a < b && b < c) || a == c) {
    /* ... */
}

“読みやすさのためのカッコ”は良い習慣

カッコは、コンパイラのためというより 人間のため に付けることが多いです。
数年後の自分にも効きます。

結合規則のおさらい(同じ強さが並んだときの順番)

種類どっち向き?イメージ
左結合が多い10 - 5 + 2左→右(10 - 5) + 2
代入は右結合a = b = c = 5右→左c=5 → b=c → a=b

「同じ優先順位の演算子が連続したら、どっちから評価するか」を決めるのが結合規則です。

確認問題:6章チェック

○か×を付けてください。

① int a = 7, b = 2; double x = a / b; のとき、x は 3.5 になる。
② a % b は、整数に対してのみ使える。
③ a / 0 は実行時エラーになるが、a % 0 は問題なく動く。
④ 単項 - は値の符号を反転させる演算子である。
⑤ double x = (double)(3 / 2); のとき、x は 1.5 になる。
⑥ (double)3 / 2 は、浮動小数点の割り算になり 1.5 を得られる。
⑦ キャストは演算のために一時的に型を変えるだけで、変数の型そのものは変わらない。
⑧ a と b が int のとき、(double)a / b と (double)(a / b) は同じ結果になる。
⑨ 丸括弧は、演算子の優先順位を強制的に変えられる。
⑩ コンマ演算子は、左から順に式を評価し、最後の式の値を全体の値として返す。

解答と解説

① ×
a / b は int 同士なので整数除算です。7 / 2 は 3 になり、x には 3.0 が入ります。3.5 が欲しいなら (double)a / b のように計算前に型を変えます。

② ○
% は剰余なので整数専用です。浮動小数点には使えません。

③ ×
a / 0 も a % 0 も、0で割るので実行時エラーになり得ます。クラッシュの原因になります。

④ ○
単項 - は符号反転です。a が正なら負に、負なら正にします。

⑤ ×
3 / 2 が先に int で計算されて 1 になり、そのあと double 化されるので 1.0 になります。1.5 にはなりません。

⑥ ○
(double)3 / 2 は 3 が double 扱いになり、全体が浮動小数点の割り算になります。結果は 1.5 です。

⑦ ○
キャストは一時的な変換です。変数そのものの型が永久に変わるわけではありません。

⑧ ×
(double)a / b は小数が出ますが、(double)(a / b) は先に整数除算して手遅れになります。結果が変わることが多いです。

⑨ ○
丸括弧で計算順序を明示でき、優先順位に関係なく先に計算させられます。

⑩ ○
コンマ演算子は左から評価し、最後の式の値が全体の値になります。

解説補足:コンマ演算子(,)は「区切り」じゃないことがある

コンマはいつも区切りに見えますが、C言語には コンマ演算子 という別物があります。
見分け方は、「式として使って値を返しているかどうか」です。

コンマ演算子の特徴

  • 左から順に評価する
  • 最後の式の値を返す

例1:1行で複数の代入をして、最後の値を使う

ファイル名:6_11_2.c

#include <stdio.h>

int main(void)
{
    int x = 1, y = 2, z;

    z = (x = 8, y = 9);  /* 最後の式 y=9 の値(9)がzに入る */

    printf("x=%d, y=%d, z=%d\n", x, y, z);
    printf("メッセージ: コンマ演算子は最後の式の値を返すよ。\n");

    return 0;
}

この実行後は x=8, y=9, z=9 になります。

例2:for の中でよく見るコンマ(区切りと演算子が混ざる)

for の初期化部や更新部では、複数の式を書きたいのでコンマがよく出ます。

ファイル名:6_11_3.c

#include <stdio.h>

int main(void)
{
    int i, j;

    for (i = 0, j = 5; i <= j; i++, j--)
        printf("i=%d, j=%d\n", i, j);

    return 0;
}

ここでのポイントはこれです。

  • for の ( ) の中で i = 0, j = 5 と書けるのは、コンマ演算子として左から評価しているから
  • printf の i=%d, j=%d のカンマは、単なる文字列の一部で演算子ではない
  • printf の引数を区切るカンマは、ただの区切りであって、コンマ演算子の「最後の値を返す」みたいな意味はありません

注意:コンマ演算子は便利だけど、式が複雑になると読みにくい

1行で色々できてしまうので、やりすぎると自分でも読めなくなることがあります。
学習中は、必要な場面(for の初期化・更新)を中心に使うのがちょうどいいです。