当前位置: 首页 > news >正文

C++ 表达式求值优先级、结合律与求值顺序(五十九)

1. 运算符优先级与结合律

  • 优先级(Precedence) 决定未加括号时运算符如何“绑”在一起:
    5 + 10 * 20 / 2;  // 等同于 5 + ((10 * 20) / 2)
    
  • 结合律(Associativity) 决定同级运算符的结合方向:
    • 左结合(大多数二元运算符):20 - 15 - 3(20 - 15) - 3
    • 右结合(赋值、条件、一些复合赋值运算符):a = b = ca = (b = c)

技巧:遇复杂表达式,加括号明确意图。

2. 求值顺序与短路

  • 默认情况下,C++ 并不保证子表达式的求值顺序——除非运算符明确规定。
  • 短路求值
    • &&:只有左侧为真时才求右侧
    • ||:只有左侧为假时才求右侧
    • ?::仅求选中的那分支
  • 逗号运算符 ,:先求左侧(结果丢弃),再求右侧,返回右侧结果。
int x = (f1(), f2());  // 只调用 f1() 后再调用 f2()

3. 算术运算符

运算符功能结合律
+ - (一元)符号取正/取负
* / %乘、除、取余
+ - (二元)加、减
  • 整数除法 向零截断(C++11 起)。
  • 取余 遵循 (a/b)*b + a%b == a

4. 关系与逻辑运算符

运算符功能结合律
< <= > >=关系比较
== !=相等/不等
!逻辑非
&&逻辑与
``

注意:不能把布尔字面值 true/false 与非布尔表达式比较,易引发歧义。

5. 赋值与复合赋值

  • 普通赋值 =右结合,左侧必须是非常量左值,返回左值本身。
  • 复合赋值 +=-=*=|=、…:等价于 a = a op b,但只评估一次 a
// 更安全、更高效
sum += val;
mask |= (1UL << bit);

6. 递增/递减运算符

形式含义求值结果
++i前置:先加 1,再返回左值左值
i++后置:先返回旧值,再加 1右值

警惕 在同一表达式中同时修改和读取同一变量,会导致未定义行为!

7. 条件与逗号运算符

  • 条件 cond ? A : B右结合,只计算所选分支。
  • 逗号 E1, E2左结合,顺序求值,返回 E2
// 条件表达式须两边类型可兼容或可转换
auto grade = (score < 60 ? "Fail" : "Pass");// for 循环中同时更新两个变量
for (int i = 0, c = 100; i < 10; ++i, --c) {}

8. 位运算符

运算符功能结合律
~按位取反
<<左移
>>右移
&按位与
^按位异或
|按位或

提示:用于掩码、标志位或快速乘除以 2 的幂。但要注意符号扩展与未定义行为。

9. sizeof 运算符

  • 编译时 常量表达式,不触发构造/析构、函数调用或解引用。
  • 返回 size_t:可用于数组维度、static_assert
  • 数组名不退化sizeof arr == N * sizeof(arr[0])
int a[10];
static_assert(sizeof a / sizeof a[0] == 10, "元素个数应为 10");

结语

透彻理解 C++ 的运算符优先级、结合律与求值顺序,能帮你:

  • 避免未定义行为:防止同时修改与读取、写错括号导致逻辑混乱
  • 提高性能和可读性:恰当运用复合赋值、短路逻辑、位运算
  • 写出更健壮的模板代码:掌握 sizeof、常量表达式与 static_assert

下次再碰到复杂表达式,请先画出运算符“优先级地图”,加上必要的括号,写出让人“一眼就懂”的 C++ 代码。祝你编码愉快!

相关文章:

  • 维度的语法:从列表的散文到 ndarray 的十四行诗
  • PostgreSQL oracle_fdw 扩展解析
  • 【DeepSeek认证】最好的MODBUS调试工具
  • 【JAVA ee初阶】多线程(3)
  • 设计模式(状态模式)
  • 2025年- H11-Lc118-53.最大子数组和(普通数组)---java版
  • WPF 程序监控硬件设备状态变化的实现方案
  • MaxScript二维图形布尔(并)运算
  • 【iOS】OC源码阅读——alloc源码分析
  • Android显示学习笔记本
  • 第一天 车联网定义、发展历程与生态体系
  • 机器学习中的标签策略:直接标签、代理标签与人工数据生成
  • 清华大学正式成立人工智能医院
  • 北重数控滑台加工厂家:汽车零部件试验铁地板-安全性能的测试方法
  • 代码片段存储解决方案ByteStash
  • 八大排序——直接插入排序/希尔排序
  • python使用dlib的5点和68点的人脸检测
  • 深入理解缓存淘汰策略:LRU 与 LFU 算法详解及 Java 实现
  • springboot 实现敏感信息脱敏
  • OpenCV 图形API(69)图像与通道拼接函数------将一个 GMat 类型的对象转换为另一个具有不同深度GMat对象函数convertTo()
  • 海南儋州市委副书记任延新已赴市人大常委会履新
  • 美乌总统梵蒂冈会谈,外交部:望有关各方继续通过对话谈判解决危机
  • 上海“生育友好岗”已让4000余人受益,今年将推产假社保补贴政策
  • 四川邻水县县长石国平拟任县(市、区)党委书记
  • 央视曝光假进口保健品:警惕!保税仓发货不等于真进口
  • 女儿被偷拍后,一个父亲的战斗