调试一个权限判断,代码写着 if (flags & 0x0F == 0x0F),本来想确认低四位全是 1,结果只设置了最低位的记录也进了分支。问题不在按位与,在优先级:== 比 & 先算,表达式实际变成了 flags & 1。

先记住这张大致顺序

从高到低,常见的是后缀、前缀、乘除、加减、移位、关系、相等、按位与、异或、按位或、逻辑与、逻辑或、条件、赋值、逗号。不用背全表,但要记住相等比按位与高,移位比加减低。拿不准就加括号,括号不会让代码变慢,只会让意图更清楚。

移位和加法的组合最容易错

int x = 1 << 2 + 3;

很多人以为先左移得到 4,再加 3 得 7;实际加法先算,等价于 1 << 5,结果是 32。要表达先移位,写成 (1 << 2) + 3。位运算和比较混在一起时也一样,if ((flags & 0x0F) == 0x0F) 才是想判断低四位。

指针和自增的优先级

*p++ 等价于 *(p++),先取当前地址的值,再把指针往后移;(*p)++ 才是把指向的值加一。++*p 则是先对 *p 自增。三种写法含义完全不同,调试时看汇编或打印地址最直接。c语言优先级表只能帮你读代码,真正写业务时还是拆成两行更稳。

还有一类是宏和逗号。宏参数里的表达式如果没有加括号,展开后优先级可能完全变样;函数式宏常用的 do { } while (0) 也是为了避免分号问题。读旧代码时,看到宏先展开再判断,别直接按表面顺序理解。

结合性也别忽略

赋值运算符从右往左结合,a = b = c 先执行 b = c,再把 b 的值赋给 a。条件运算符 ?: 也是右结合,嵌套时容易读错。函数调用、数组下标、成员访问属于同一档,从左往右结合。优先级决定谁先算,结合性决定同档怎么算,这两件事要分开看。

实际写代码时,看到一行里同时出现按位与、相等、移位和加法,先拆括号;看到 *p++,先确认作者想移动指针还是改值。编译器警告开到 -Wall,再配 clang-tidy,能拦下一部分可疑写法。c语言优先级不是考试题,记住几个高频坑,比背完整表格有用。