
C言語基礎|演算子の優先順位と結合性
カッコなしで書いた式、あなたの想像どおりに動いてる?――Cの優先順位と結合性を味方にしよう。
式が長くなるほど「読み違い」がバグになる
C言語は演算子が豊富で、式を短く書けるのが魅力です。
でもその分、カッコを省略した式は「どこから計算されるか」を読み違えやすくて、地味〜に痛いバグの原因になります。
ここで押さえたいのは2つだけ。
- 優先順位:どの演算子が先に計算されるか
- 結合性:同じ優先順位が並んだとき、左から結ぶか右から結ぶか
この2つがわかると、式の意味がスッと読めるようになりますよ。

優先順位ってなに?
優先順位は「どれが先に計算されるか」のルールです。
身近な数学と同じで、加算より乗算が先、みたいな感じですね。
優先順位のイメージ

説明
見た目で左から順に計算しているわけじゃなく、優先順位が高い演算子(この例では *)が先に評価されます。
結合性ってなに?
結合性は「同じ優先順位の演算子が続いたとき、どっちにまとまるか」のルールです。
左結合と右結合

図の説明
例えば - は左結合なので、5 - 3 - 1 は (5 - 3) - 1 になります。
一方、代入 = は右結合なので、a = b = 1 は a = (b = 1) になります。
優先順位の“実務用”詳細表(よく使うものを中心に)
上ほど優先順位が高いです。
「形式」欄は見た目のパターンをそのまま書いてあります。
よく使う演算子中心・優先順位と結合性
| 優先順位 | 演算子(代表) | 形式例 | 何をする?(ざっくり) | 結合性 | 実務メモ(落とし穴) |
|---|---|---|---|---|---|
| 1 | 関数呼び出し | f(x) | 関数を呼ぶ | 左 | 引数の中はさらに優先順位が効く |
| 添字 | a[i] | 配列アクセス | 左 | i++ を入れると読みづらい | |
| メンバ参照 | s.m | 構造体メンバ | 左 | . は強い | |
| ポインタメンバ | p->m | ポインタ先メンバ | 左 | -> も強い | |
| 後置増減 | x++ / x-- | 使った後に増減 | 左 | 値としては「増える前」が使われる | |
| 2 | 前置増減 | ++x / --x | 先に増減 | 右 | 代入と絡めると事故るので単独推奨 |
| 単項 + - | +x / -x | 符号 | 右 | -10 は「定数」ではなく「10に単項-」 | |
| 論理否定 | !x | 0なら1、非0なら0 | 右 | 真偽値に寄せる | |
| ビット反転 | ~x | 全ビット反転 | 右 | 符号付きに対する意味を意識 | |
| アドレス | &x | アドレス取得 | 右 | 単項 & と ビットAND & は別物 | |
| 間接参照 | *p | ポインタ参照 | 右 | 単項 * と 乗算 * は別物 | |
| sizeof | sizeof x / sizeof(型) | サイズ取得 | 右 | sizeof(式)は式を評価しない(※VLA除く) | |
| キャスト | (型)x | 型変換 | 右 | 強いので影響範囲をカッコで明示すると良い | |
| 3 | 乗除剰余 | x*y / x/y / x%y | 算術 | 左 | 整数除算は小数切り捨て |
| 4 | 加減 | x+y / x-y | 算術 | 左 | ここは直感通り |
| 5 | シフト | x<<n / x>>n | ビット移動 | 左 | 加減より弱いので x<<1+2 は要注意 |
| 6 | 関係(大小) | < <= > >= | 比較 | 左 | 連鎖比較 x<y<z は意図どおりにならない |
| 7 | 等価 | == != | 等しい? | 左 | < より弱い(ここが直感とズレやすい) |
| 8 | ビットAND | x & y | ビット論理積 | 左 | == より弱いので x & y == 0 は危険 |
| 9 | ビットXOR | x ^ y | ビット排他 | 左 | フラグ反転などに使う |
| 10 | ビットOR | x | y | ビット論理和 | 左 | フラグセットに使う |
| 11 | 論理AND | x && y | 真偽のAND | 左 | 短絡評価あり(左が偽なら右を見ない) |
| 12 | 論理OR | x || y | 真偽のOR | 左 | 短絡評価あり(左が真なら右を見ない) |
| 13 | 条件 | c ? a : b | 三項演算 | 右 | ネストは読みにくいのでカッコ推奨 |
| 14 | 代入 | = += -= … | 代入 | 右 | a=b=1 は a=(b=1) |
| 15 | コンマ | x, y | 順に評価して最後を返す | 左 | for の中以外は避けるのが無難 |
この表の使い方
「どっちが先?」と思ったら、表で上にある演算子が先です。
「同じ段に並んでたら?」は、結合性で左右が決まります。
“混乱しやすい組み合わせ”早見表(ここが一番役に立つ)
実務でミスが多いのは、だいたいここです。
よくある落とし穴と安全な書き方
| 書き方 | 実際の解釈 | ありがちな勘違い | 安全な書き方 |
|---|---|---|---|
| x << 1 + 2 | x << (1 + 2) | (x << 1) + 2 | (x << (1 + 2)) または ((x << 1) + 2) |
| a & b == 0 | a & (b == 0) | (a & b) == 0 | ((a & b) == 0) |
| x < y == z | (x < y) == z | x < (y == z) | (x < y) && (y == z) など意図を分解 |
| mask & 1 << n | mask & (1 << n) | (mask & 1) << n | (mask & (1U << n)) |
| !x & 1 | (!x) & 1 | !(x & 1) | !(x & 1) と書く |
| a && b | 真偽でAND | a & b と同じ | フラグなら &、条件なら && と使い分け |
| a || b | 真偽でOR | a | b と同じ | 条件なら ||、ビットなら | |
表の説明
- == は & より強いので、ビット判定はカッコ必須級
- << は + より弱いので、シフト量に式を入れるときは特に注意
- 論理演算子とビット演算子は目的が違う(値の扱いが根本的に違う)
結合性で読みが変わる例
同じ優先順位が並ぶときの結び方
| 演算子の例 | 結合性 | 例 | 実際のまとまり |
|---|---|---|---|
| - / % << >> < <= > >= == != & ^ | && || | 左結合 | 5 - 3 - 1 | (5 - 3) - 1 |
| = や += など | 右結合 | a = b = 7 | a = (b = 7) |
| ?: | 右結合 | a ? b : c ? d : e | a ? b : (c ? d : e) |
表の説明
代入が右結合なのは、連鎖代入が書ける理由そのものです。
条件演算子 ?: も右結合なので、入れ子になるときはカッコで読みやすくするのが親切です。
サンプルプログラム
ここでは「優先順位と結合性で結果が変わる」ことを、短いプログラムで体感します。
プロジェクト名:chap7-27-1 ソースファイル名:chap7-27-1.c
// 優先順位と結合性の違いを確認する
#include <stdio.h>
int main(void)
{
int a = 6; // 110
int b = 2; // 010
int x = 8;
printf("優先順位と結合性の確認をします。\n\n");
// 1) シフトと加算の優先順位
printf("【例1】x << 1 + 2 と (x << 1) + 2 を比べます。\n");
printf("x << 1 + 2 = %d\n", x << 1 + 2);
printf("(x << 1) + 2 = %d\n\n", (x << 1) + 2);
// 2) & と == の優先順位(落とし穴)
printf("【例2】a & b == 0 と (a & b) == 0 を比べます。\n");
printf("a & b == 0 = %d\n", a & b == 0);
printf("(a & b) == 0 = %d\n\n", (a & b) == 0);
// 3) 代入は右結合
printf("【例3】代入は右結合なので、連鎖代入ができます。\n");
int p, q;
p = q = 7;
printf("p = %d, q = %d\n", p, q);
return 0;
}
このプログラムで見えること
- x << 1 + 2 は x << (1 + 2) と同じ解釈になりやすい
- a & b == 0 は (a & b) == 0 ではない
- p = q = 7 が動くのは、= が右結合だから
登場する命令(構文)と何をする命令か
printf 関数
書式
- printf(書式文字列, 引数1, 引数2, ...);
何をする命令?
標準出力(通常は画面)に文字や数値を表示します。今回のように、式の評価結果を確認するのに便利です。
代入演算子 =
書式
- 左辺 = 右辺
何をする命令?
右辺の値を左辺(変数など)に格納します。右結合なので a = b = 1 のように連鎖ができます。
シフト演算子 << >>
書式
- a << b
- a >> b
何をする命令?
整数のビット列を左右にずらします。優先順位は + - より低いので、x << 1 + 2 が x << (1 + 2) になりやすい点が重要です。
ビットAND &
書式
- a & b
何をする命令?
a と b をビットごとにANDします。条件判定で使うときは (a & mask) == 0 のようにカッコを付けるのが安全です。
等価演算子 ==
書式
- a == b
何をする命令?
a と b が等しいなら 1、違うなら 0 になります。& より優先順位が高いので、a & b == 0 は要注意です。
実務での安全ルール(読みやすさ優先でOK)
迷ったらこれ
| 目的 | 推奨 |
|---|---|
| 比較やビット判定を混ぜる | 必ずカッコを付ける(例:(x & mask) != 0) |
| シフトと加算を混ぜる | カッコで意図を固定する(例:x << (n + 1)) |
| 条件演算子 ?: が長い | カッコか if 文に分解する |
| 可読性が最優先 | 優先順位に頼らず、カッコで明示する |
表の説明
コンパイラは優先順位どおりに解釈してくれますが、人間は疲れると読み違えます。
バグを減らすなら「正しさ+読みやすさ」の両方を狙うのがいちばんです。
