問題の歴史
C言語において演算子の優先順位は、数学的および論理的な表現の計算順序を管理するために導入されました。数学の演算子には歴史的に期待される優先順位がありますが(代数のように)、多くの新しい演算子(論理、ビット単位、代入など)の出現により、状況が複雑化しました。エラーの可能性を減らし、可読性を向上させるために、演算子の優先順位と結合規則の公式リストが登場しました。
問題
多くの演算子とその多様な性質(算術、比較、代入、論理、インデックス付けなど)があるため、複雑な式を作成するときにあいまいさが生じます。これらを正しく理解しないと論理的なエラーや明白でないバグを引き起こすことになり、特にビット単位と論理演算子、ポインタ、インクリメント、三項演算子との組み合わせでは危険です。
解決策
コードの例:
#include <stdio.h> int main() { int a = 1, b = 2, c = 3, d; d = a + b * c; // b*cが先に評価される: d = 1 + (2*3) = 7 printf("%d ", d); d = a + b << 1; // a + b = 3、その後3 << 1 (6) printf("%d ", d); d = a < b ? a++ : b++; printf("%d ", d); // a < bが真 => d = a (1), aは後で増加 }
重要な特徴:
括弧を忘れた場合、式x = y > z ? y : z;はどのような結果を返しますか?
回答:三項演算子?:は>よりも低い優先順位を持つため、まず(y > z)が評価され、その後yとzから選択されます。しかし、代入と組み合わせると予期せぬ効果が生じる可能性があります。常に括弧を使用する方が良いです:x = (y > z) ? y : z;。
式*p++はどのような結果になりますか、なぜですか?
回答:ポストインクリメント(++)演算子は、間接参照()よりも高い優先順位を持つため、p++は(p++)になります:まずpが使われてインクリメントされ、その後間接参照されます。これは++p(インクリメント後の間接参照)とは異なる結果を引き起こします。
式a & b == cはなぜ期待通りに動作しないのですか?
回答:演算子==は&よりも高い優先順位を持っているため、式はa & (b == c)として解析され、(a & b) == cとはならず、予期しない結果を生じます。望ましい論理には括弧を使用する必要があります。
if ((a & b) == c) { ... }
ネガティブケース
コーディングの最適化中に、プログラマーは括弧なしで複数の演算子を組み合わせました:if( mask & flag == 0 ) ...、その結果、検証ロジックが誤り、システムの動作が失敗しました。
利点:
欠点:
ポジティブケース
明示的なグループ化の使用:if( (mask & flag) == 0 ) ...、ロジックは明確で、フラグを簡単に変更できます。
利点:
欠点: