Contents
1️⃣ 演算子とは何か、なぜ優先順位が必要なのか
-
演算子の役割
変数や定数に対して「計算」「比較」「代入」などの操作を指示する記号です。式は左から右へ順次評価されますが、複数の演算子が混在すると実行順序が結果に直結します。 -
優先順位がもたらす影響
- 同じ式でも評価順序が変われば得られる値は大きく異なる。
- 未定義動作やオーバーフロー、ポインタ演算の不整合など深刻なバグの温床になる。
例
a + b * cは掛け算が先に評価され、実際にはa + (b * c)と同じです。
逆に括弧で囲めば意図を明示できるので、バグ防止につながります。
2️⃣ C23 に基づく全演算子一覧と結合規則
2.1 優先順位表(高→低)
| 順序 | 演算子・カテゴリ | 結合性 |
|---|---|---|
| 1 | 後置インクリメント/デクリメント expr++ expr--関数呼び出し ()配列添字 []メンバアクセス . -> |
左 |
| 2 | 前置インクリメント/デクリメント ++expr --expr単項演算子 + - ! ~ * & sizeof _Alignof |
右 |
| 3 | 乗算・除算・剰余 * / % |
左 |
| 4 | 加算・減算 + - |
左 |
| 5 | ビットシフト << >> |
左 |
| 6 | 関係演算子 < <= > >= |
左 |
| 7 | 等価比較 == != |
左 |
| 8 | ビットAND & |
左 |
| 9 | ビットXOR ^ |
左 |
| 10 | ビットOR \| |
左 |
| 11 | 論理AND && |
左 |
| 12 | 論理OR \|\| |
左 |
| 13 | 条件演算子 ?: |
右 |
| 14 | 代入演算子 = += -= *= /= %= <<= >>= &= ^= \|= |
右 |
| 15 | カンマ , |
左 |
注:上記は ISO/IEC 9899:2023(C23)正式規格の第6.5節に基づいています。
出典としては、公式ドラフト(ISO C23 Draft N2596)と cppreference.com の C operators ページを参照しました。
2.2 結合性の概要
| 結合性 | 意味 |
|---|---|
| 左結合 | 同一優先度で左側から右側へ評価(例:a - b - c → ((a - b) - c)) |
| 右結合 | 右側から左側へ評価(例:a = b = c → (a = (b = c))) |
3️⃣ カテゴリ別演算子解説と実践サンプル
3.1 算術演算子 (* / % + -)
- ポイント:乗除算が加減算より高い優先度。
- サンプル
|
1 2 3 |
int a = 3 + 4 * 2; // → 11 (3 + (4*2)) int b = (3 + 4) * 2; // → 14 ((3+4) * 2) |
複雑な計算は必ず括弧で明示し、意図と実装を一致させましょう。
3.2 ビット演算子 (& \| ^ << >>)
- ポイント:すべて左結合。シフト演算は優先度が低いため、
*や+と混在する場合は注意。 - サンプル
|
1 2 3 4 |
uint8_t mask = 0xF0; uint8_t val = 0x5A; uint8_t res = (val & mask) >> 4; // → 0x05 |
3.3 論理・比較演算子 (&& || < <= > >= == !=)
- ポイント:左結合で短絡評価(
&&は左が偽なら右は評価されない)。副作用を含む式は括弧で保護。
|
1 2 3 4 5 |
int i = 0; if (i++ && func()) { // func() は呼ばれない /* ... */ } |
3.4 条件演算子と代入 (?:, = += …)
- ポイント:どちらも右結合。連続代入は可読性が低下しやすいので、行を分割することを推奨。
|
1 2 3 4 |
int a, b, c; a = b = c = 10; // 推奨しない例 int max = (x > y) ? x : y; // 括弧で全体を囲むと見やすい |
3.5 sizeof と型演算子
- ポイント:単項演算子として最上位に位置し、右結合。型名は必ず括弧で囲むか、
sizeof exprの形で使用する。
|
1 2 |
size_t sz = sizeof(int) + 2; // (sizeof(int)) + 2 と同等 |
3.6 ポインタ・配列・関数呼び出し
- ポイント:
[],(),.,->は最上位で左結合。ポインタ演算とデリファレンスの組み合わせは括弧で明示することが必須。
|
1 2 3 4 |
int arr[5] = {0,1,2,3,4}; int *p = &arr[2]; int val = *p++ + *(p+1); // (*p++) + *(p+1) |
4️⃣ よくある落とし穴と対策
| ケース | 典型的な問題 | 安全に書くポイント |
|---|---|---|
| 同一変数への複数更新 | i++ + ++i は未定義動作 |
副作用は式を分割してステートメント化 |
| 符号付き整数のオーバーフロー | int8_t a = 120; a += 10; → 未定義 |
int_fastN_t 系や安全算術ライブラリで事前チェック |
| ポインタ演算とデリファレンスの混在 | *p + 1 と *(p + 1) の違い |
意図した対象を必ず括弧で囲む |
| ビットシフトと論理演算の同時使用 | a & b << c && d → 読みにくい |
優先順位が不明な式はすべて括弧で整理 |
5️⃣ 覚え方・実務で使えるベストプラクティス
- 語呂合わせ
- 「後置→単項→乗除→加減→シフト→比較→等価→AND →XOR →OR →論理AND →論理OR →条件 →代入」
- マインドマップ
-
「優先度」→「カテゴリ」→「演算子」の階層をツール(例:XMind)で可視化。
-
必ず括弧で明示
c
int result = (a + b) * (c - d); // 直感的に評価順序が分かる -
チェックリスト活用(抜粋)
| No | 演算子 | 優先度 | 結合性 | 正しい書き方 |
|---|---|---|---|---|
| 1 | * / % |
3 | 左 | (x * y) / z |
| 2 | && |
11 | 左 | a && b && c |
| 3 | ?: |
13 | 右 | (cond) ? a : b |
| … | … | … | … | … |
6️⃣ 組み込み開発・ツールでの実践的確認方法
6.1 コンパイラ警告を最大限に活用
|
1 2 |
gcc -std=c23 -Wall -Wextra -Wshadow -Werror -O2 source.c |
- 警告がエラーになるように設定すれば、優先順位ミスや未定義動作をコンパイル時に捕捉できます。
6.2 Compiler Explorer (Godbolt)
- 手順:https://godbolt.org/ → 言語
C (c23)→ コンパイラ例gcc 13.2→ ソース貼り付け → アセンブリで評価順序を確認。 - 複数コンパイラ(gcc, clang, arm-none-eabi-gcc)を同時に比較でき、組み込みターゲット固有の最適化差も把握可能。
6.3 Clang の AST ダンプ (-fdump-tree-original)
|
1 2 |
clang -std=c23 -fdump-tree-original source.c -o /dev/null |
- 出力に演算子がどの順序で評価されるかがテキスト化され、CI に組み込んで自動チェックが可能。
7️⃣ 参考文献・情報元の最新性確認
| 項目 | URL | 内容 | 確認日 |
|---|---|---|---|
| ISO/IEC 9899:2023(C23)正式規格 | https://www.iso.org/standard/79358.html | 標準本文、演算子優先順位・結合性 | 2024‑10‑01 |
| C23 Draft N2596(公開ドラフト) | https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2596.pdf | 第6.5節に詳細な表が掲載 | 2024‑09‑15 |
| cppreference – C operators | https://en.cppreference.com/w/c/language/operator_precedence | 最新のコンパイラ実装情報を反映した優先順位一覧 | 2024‑11‑02 |
| gcc マニュアル(C23 オプション) | https://gcc.gnu.org/onlinedocs/gcc/C-Extensions.html#C-Extensions | -std=c23 の挙動解説 |
2024‑08‑20 |
上記リンクはすべて執筆時点で最新バージョンを確認済みです。
8️⃣ まとめ
- 演算子の優先順位と結合性を正しく把握することで、未定義動作や意図しない結果を防げます。
- C23 では従来通りの優先順位体系であり、
::のようなスコープ解決演算子は存在しません(C++ 専用)。 - 式が複雑になるほど括弧で明示し、コードレビューや静的解析ツールの警告を活用しましょう。
- 公式規格と信頼できるリファレンス(cppreference 等)を情報源にすれば、常に最新かつ正確な知識が得られます。
実務での一番のコツは「見た目と評価順序を合わせる」ことです。
まずは自分の書く式に対して “このままで本当に正しいか?” と疑問を持ち、必要ならすぐに括弧を足す習慣を身につけてください。