C's precedence rules are not in fact, there are cases where they can be considered really bad.
These are the current rules in C2:
1. (),.*, ->*
2. !,~
3. *, /, %
4. -, +
5. <<, >>
6. >=, <=, >, <
7. ==, !=
8. &
9. ^
10. |
11. &&
12. ||
13. ?
14. =, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |=
15. ,
I would suggest a flatter and more reasonable precedence order:
1. (),.*, ->*
2. !,~
3. *, /, %
4. <<, >>
5. &, ^, |
6. -, +
7. ==, !=, >=, <=, >, <
8. &&, ||
9. ?
10. =, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |=
11 ,
This means that we cant write something like a || b && c || d && e and expect anything other left-to-right evaluation. In my opinion the operator precedence rules here are allowing hard-to-read code.
We're also removing the common pitfall of a << 3 + b << 2, it's no longer evaluated to (a << (3 + b)) << 2 but instead (a << 3) + (b << 2).
Flattening the bitwise operators follows the same rationale as for logical and/or. An expression such as a | b ^ c & d which has the evaluation of (a | (b ^ (c & d))) might be unexpected for many.
Moving the bitwise operators before comparisons finally allows us for the intuitive code of a & b == 0 instead of the currently required (a & b) == 0. I would say that the standard evaluation of a & (b == 0) is virtually never intended.
We'd be removing three levels of precedence and creating code that's easier to understand and remember. (And the bitwise operator precedence of C should be considered a bug more than anything.)
Other languages with similar precedence rules: Julia, Nim, Zig, Python.