if文の条件式で = と == を間違えて常に真になる
比較のつもりで==と書くべきところを=と書いてしまうと、比較ではなく代入になり、条件は代入した値の真偽で判定されます。エラーにはならず、意図しない分岐が起こります。
なぜエラーが出ないのか
出力: yes(okが0のはずなのに実行される)
(エラーなし)- Cは何も報告しません。コンパイルも実行も正常に完了するためです
出力: yes(okが0のはずなのに実行される)- 実際の挙動 — 期待した結果と食い違っている箇所
見つけ方- エラーが出ないので、出力を目で確かめるか、コードを目で追うしかありません。この種の誤りが最も発見が遅れます
このエラーが出る典型パターン
パターン1
1 #include <stdio.h> 2 3 int main(void) { 4 int ok = 0; 5 if (ok = 1) { ^ 6 printf("yes\n"); 7 } 8 return 0; 9 }
if (ok = 1)は比較ではなく代入です。okに1が代入され、その代入結果(1)が真として評価されるため、常にブロックが実行されます。
直し方: = を == にします。
パターン2
1 #include <stdio.h> 2 3 int main(void) { 4 int age = 15; 5 if (age = 18) { ^ 6 printf("adult\n"); 7 } else { 8 printf("minor\n"); 9 } 10 return 0; 11 }
if (age = 18)はageに18を代入したうえで、その値(18、真)を条件として使ってしまいます。ageの実際の値である15は無視されます。
直し方: = を == にします。
パターン3
1 #include <stdio.h> 2 3 int main(void) { 4 int found = 0; 5 if (found = 1) { ^ 6 printf("found\n"); 7 } else { 8 printf("not found\n"); 9 } 10 return 0; 11 }
=は代入、==は比較です。1文字の書き間違いですが、Cはこれを文法的に正しい式として受け入れてしまうため、エラーにはなりません。
直し方: = を == にします。
パターン4
1 #include <stdio.h> 2 3 int main(void) { 4 int active = 0; 5 if (active = 1) { ^ 6 printf("running\n"); 7 } else { 8 printf("stopped\n"); 9 } 10 return 0; 11 }
if (active = 1)はactiveに1を代入し、その結果(真)を条件として使ってしまいます。
直し方: = を == にします。
パターン5
1 #include <stdio.h> 2 3 int main(void) { 4 int level = 3; 5 if (level = 5) { ^ 6 printf("max\n"); 7 } else { 8 printf("not max\n"); 9 } 10 return 0; 11 }
levelの実際の値(3)に関わらず、代入された5が真として扱われてしまいます。
直し方: = を == にします。
よくある誤解
Pythonでは代入を式の中で使えないため構文エラーになりますが、Cでは代入も1つの式として値を持つため、if文の条件式にそのまま書けてしまいます。0以外の値は真と評価されるため、多くの場合そのまま「常に真」になります。
実務での勘所
この事故を機械的に防ぐ手立てが2つあります。1つはコンパイラの警告オプション(-Wallに含まれる-Wparentheses)を有効にすることで、if (x = y)のような代入を条件式に書くと警告してくれます。もう1つは、比較の左右を入れ替えて定数を左に置く書き方(if (5 == x)のような、通称Yoda記法)です。誤って=と打ってもif (5 = x)はエラーになるため、コンパイラがそのミスを強制的に検出してくれます。