【C语言·007】算术运算符的优先级与结合性规则详解

  • 时间:2025-11-13 21:46 作者: 来源: 阅读:1
  • 扫一扫,手机访问
摘要:许多人第一次被 C 语言“整顿”的瞬间,往往来自一行看似无害的表达式:为什么 1 + 2 * 3 是 7 而不是 9?为什么 a/b*c 和 a/(b*c) 完全不同?再列如把 i++ 混进来,程序甚至可能直接掉进“未定义行为”的深坑。本文从工程实践出发,把“算术运算符的优先级与结合性”讲清楚,并配上容易踩坑的例子与可操作的改写准则。一、算术运算符家族与“两个核心维度”在 C 里,围绕数值计算的常

【C语言·007】算术运算符的优先级与结合性规则详解

许多人第一次被 C 语言“整顿”的瞬间,往往来自一行看似无害的表达式:为什么 1 + 2 * 3 是 7 而不是 9?为什么 a/b*ca/(b*c) 完全不同?再列如把 i++ 混进来,程序甚至可能直接掉进“未定义行为”的深坑。本文从工程实践出发,把“算术运算符的优先级与结合性”讲清楚,并配上容易踩坑的例子与可操作的改写准则。

一、算术运算符家族与“两个核心维度”

在 C 里,围绕数值计算的常见运算符主要有:

  • 一元:+(正号)、-(取负)、++(自增)、--(自减)
  • 二元:*/%+-
  • 括号:( )(分组,改变默认结合顺序;不是运算符,但常与优先级一起讨论)

判断表达式值的两个核心维度

  1. 优先级(precedence):谁先算。
  2. 结合性(associativity):同优先级从左往右还是从右往左。

牢记一句话:先看优先级,再按结合性

二、只谈算术的“最小必记”表

下面这张表只保留算术相关条目,按从高到低排列,后缀/前缀也标出结合性:

层级

运算类别

代表

结合性

最高

括号分组

(expr)

—(强制分组)

后缀

后缀自增/自减

i++、i--

左结合

前缀

前缀自增/自减/一元正负

++i、--i、+i、-i

右结合

乘除模

乘、除、取余

*、/、%

左结合

加减

加、减

+、-

左结合

经验法则

乘除模优先于加减;同层级按左结合。

一元运算(如 -i++i)整体早于乘除;后缀 i++ 优先级高于前缀 ++i

括号能“越级”,是最稳的“保险丝”。

三、从规则到结果:逐步拆解 6 个表达式

例 1:基础混合

int v = 1 + 2 * 3 - 4 / 2; // 1 + 6 - 2 -> 5

先乘除(左结合),再加减,得到 5

例 2:同级左结合的威力

int v = 24 / 5 % 3; // (24/5)=4,再 4%3=1 -> v=1

若“凭感觉”写成 24 / (5 % 3),结果会变成 12,完全不同。

例 3:一元负号与乘法

int a = -2 * 3 + 1; // (-2*3)=-6,再 +1 -> -5

一元 - 在乘除之前结合到常量上。

例 4:自增参与但不作死

int i = 3;
int x = (i++) + 2; // 使用后再加1:x=5,i=4(安全)

只有一处修改 i,且另一侧不依赖 i,可读性与行为都清晰。

例 5:反例:未定义行为(UB)

int i = 2;
int y = i++ * ++i; // UB:一个序列点内对 i 的多次修改/读取冲突

这不是“结果不确定”,而是程序行为未定义——编译器可以做任何事情。修正:

int i = 2;
int a = i++;      // a=2, i=3
int b = ++i;      // i=4, b=4
int y = a * b;    // y=8

例 6:同级左结合不等同“先算大括号”

double t1 = 1.0/2*2; // 0.5*2 -> 1.0
double t2 = 1/2*2;   // 0*2   -> 0    (整数除法先发生)

优先级不解决类型问题,见下一节。

四、类型提升与“常规算术转换”——看不见的裁判

运算之前,C 会做一系列隐式转换,决定以什么精度计算:

  1. 整数提升(integer promotions) charshort 等会先提升为 int(或 unsigned int),再参与运算。
  2. 常规算术转换(usual arithmetic conversions) 为了让两侧“说同一种语言”:
  3. 若任一操作数是 long double/double/float,另一侧向其提升;
  4. 否则在整数层面按“类型等级与有无符号”规则对齐到共同类型(例如 intlong long 结果为 long long)。

这些规则直接决定除法与取模的语义

  • 整数除法 /:截断趋零。例如 -7/3 == -2
  • 取模 %:余数与被除数同号,-7 % 3 == -1
  • % 只对整数有效,浮点取模请用 fmodmath.h)。

关键结论

1/2 按整数算是 01.0/2 才是 0.5

摆放顺序不变的情况下,类型决定了过程(double)a/ba/(double)b 都触发浮点除法,而 a/b 后再转 double 只是把 0 变成 0.0

有符号整数溢出是未定义行为;无符号整数按模 2^N 回绕(定义良好但常常不是你要的)。

五、五个高频坑位与可执行改写

  1. ++/-- 混进复杂表达式
  2. a += a++i = i++ + ++i(UB)
  3. ✅ 拆解成独立语句;或仅在独立行使用 i++/--i
  4. 指望优先级“自动分组”
  5. a/b*c 以为是 a/(b*c)
  6. ✅ 用括号表达意图:a / (b*c)(a/b) * c
  7. 整数与浮点混算“被降级”
  8. avg = sum / n;(整数)
  9. avg = sum / (double)n;avg = (double)sum / n;
  10. 溢出的隐蔽性
  11. int area = 100000 * 100000;(32 位溢出)
  12. long long area = 100000LL * 100000; 或使用范围检查。
  13. 宏里重复求值 #define SQR(x) ((x)*(x))
    int v = SQR(i++); // i++ 被求值两次 -> UB
  14. ✅ 改为内联函数:static inline int sqr(int x){ return x*x; }

六、工程实践的三条“硬规范”

  • 能加括号就加括号:用括号表达“设计意图”,而不是考读者记表。
  • 自增自减只做“单兵行动”:把副作用隔离到独立语句。
  • 在边界上写测试:零、负数、极大/极小值、不同平台 int 宽度、是否开启优化等。

七、十个“即刻辨析”练习(附解析)

自测时先写出你的第一反应,再对照解析找出“规则”在哪起作用。

  1. 3 + 4 * 2 - 8 / 3 3 + 8 - 2 = 9。先乘除,后加减。
  2. 24 / 5 % 3 (24/5)=44%3=1。同级左结合。
  3. -3*2 + 5 -6 + 5 = -1。一元 - 先结合到 3
  4. 1/2*21.0/2*2 :前者 0*2=0,后者 0.5*2=1.0。类型主导。
  5. 7 % -3-7 % 3 7%-3 == 1-7%3 == -1。余数与被除数同号。
  6. int i=2; int x = i++ + 2; x=4?不,是 x=4?——。应为 x=2+2=4?再加 1,i=3。 解析:后缀自增返回旧值,表达式求值后再加 1。
  7. int i=2; int y = i++ * ++i; 未定义行为。同一序列点对同一对象多次修改/读取。
  8. int a=5,b=2; double r = a/b; 2.0 而非 2.5。先整数除法,后转为 double
  9. int x=100000, y=100000; int z = x*y; :可能溢出(32 位)。用 long long z = 1LL*x*y;
  10. int n=3; int m = n+++n; :词法解析为 (n++) + n,结果 3+4=7n 先参与加法后变 4)。可读性极差,避免。

八、把规则内化为“肌肉记忆”的写法

  • 表达式=数据流 + 副作用:尽量别混。
  • 括号是文档的一部分:给未来的你和同事看。
  • 类型显式化:凡是涉及除法、边界、跨平台,先把类型对齐到你期望的精度。
  • 单元测试要“脏”:专挑负数、零、极值去打;模 0、除 0、溢出、未定义都要在测试中暴露。

当你把“优先级—结合性—类型转换”这三板斧用顺手,C 的算术表达式就不再是谜语,而是可控、可读、可维护的工程资产。

  • 全部评论(0)
最新发布的资讯信息
【系统环境|】如何在日期天数后快速加上第n天的英文后缀?(2025-11-13 22:32)
【系统环境|】法兰的基本知识(2025-11-13 22:32)
【系统环境|】「从零搭建」用 SpringBoot + 向量搜索打造智能短视频推荐系统!(2025-11-13 22:31)
【系统环境|】常用英语词语辨析105组(内容有点多,请收藏备用)(2025-11-13 22:31)
【系统环境|】英语高级词汇:asylum(2025-11-13 22:30)
【系统环境|】第1章 电气家装仪表的使用方法与技巧(2025-11-13 22:29)
【系统环境|】最快获得VC的方式#NBA2K(2025-11-13 22:29)
【系统环境|】用 VitePress 搭建电子书,绝了!(2025-11-13 22:28)
【系统环境|】时隔多年,VitePress 终于迎来了 v1.0 !(2025-11-13 22:28)
【系统环境|】每日 GitHub 探索|探索一系列热门开源项目,提升你的技能(2025-11-13 22:27)
手机二维码手机访问领取大礼包
返回顶部