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

C语言运算符优先级“潜规则”

C语言运算符优先级潜规则

  • 前言
  • 目录
  • 一、C语言中的运算符
  • 二、C语言中运算符的优先级
  • 三、帮助记忆优先级的方法
    • 1、先粗分
    • 2、再细分
    • 3、直接拿下
      • 1.算术运算符:与数学规则高度一致
      • 2. 关系运算符:特殊注意相等性判断
      • 3.位运算与逻辑运算:严谨的优先级层次
  • 四、因不明确优先级而造成的常见问题
    • 1、经典优先级陷阱案例
      • 1. 指针解引用与自增的"暧昧关系"
      • 2. 位运算与比较运算的"优先级之争"
    • 2、那些年我们踩过的优先级坑
      • 1. 移位运算与算术运算的"爱恨情仇"
      • 2. 逻辑运算的"短路特性"引发的优先级误解
    • 3、防御性编程建议
    • 4、常见优先级陷阱速查表
    • 结语


前言

当运算符开始“论资排辈”,你的代码还好吗?

亲爱的程序员朋友,你是否曾经写下 a = b + c * d,自信满满地按下编译键,结果程序跑出来的数字让你怀疑人生?

你是否在深夜调试时,盯着 if (x & y == z) 这样的代码,内心咆哮:“这TM到底先算谁?!”

别慌,你不是一个人!C语言的运算符优先级,就像一群性格迥异的大佬聚在一起开会——* 觉得自己的优先级天下第一,++ 在旁边冷笑:“呵,你算老几?”,而 = 只能卑微地等所有人吵完再干活……

本文将带你走进这场“运算符权力的游戏”,用最接地气的方式,帮你理清谁先算、谁后算,从此告别“优先级玄学”,让代码不再“薛定谔的正确”!

(友情提示:阅读本文后,你可能再也不会写出 a+++++b 这种让编译器崩溃的代码了……)


目录

一、C语言中的运算符

运算符类别运算符
下标引用、函数调用和结构成员[] () -> .
单目运算符! ~ ++ -- + - sizeof (type) * &
算术运算符+ - * / %
移位运算符<< >>
关系运算符> >= < <= == !=
位运算符& ^ |
逻辑运算符&& ||
赋值运算符= += -= *= /= %= &= ^= |= <<= >>=
条件运算符(三目运算符)expr1 ? expr2 : expr3
逗号运算符,

二、C语言中运算符的优先级

C语言运算符优先级表(由上至下,优先级依次递减)

运算符结合性
() [] -> .L-R
! ~ ++ -- + - (type) * & sizeofR-L
* / %L-R
+ -L-R
<< >>L-R
< <= > >=L-R
== !=L-R
&L-R
^L-R
|L-R
&&L-R
||L-R
= += -= *= /= %= &= ^= |= <<= >>=R-L
expr1 ? expr2 : expr3R-L
,L-R

L-R(Left-to-Right,从左到右结合)
R-L(Right-to-Left,从右到左结合)

三、帮助记忆优先级的方法

1、先粗分

优先级最高的其实并不是真正意义上的运算符,包括数组下标、函数调用操作符和各结构体成员选择操作符。

单目运算符的优先级仅次于前述运算符,在所有真正意义是的运算符中,单目运算符的优先级最高。

优先级比单目运算符要低的,接下来就是双目运算符。

双目运算符之后就是三目运算符(条件运算符)。

优先级最低的就是逗号运算符了。
在这里插入图片描述

2、再细分

需要进一步细分的就是双目运算符了,我们需要记住:在双目运算符中,算术运算符的优先级最高,移位运算符次之,关系运算符再次之,接着就是位运算符,最后是逻辑运算符。

你们可能以为我忘了双目运算符中还有一个赋值运算符,其实赋值运算符算是一个特例:赋值运算符的优先级低于三目运算符(条件运算符)
在这里插入图片描述
需要注意的最重要的两点是:

  1. 任何一个逻辑运算符或位运算符的优先级低于任何一个关系运算符。
  2. 移位运算符的优先级比算术运算符要低,但是比关系运算符要高。

3、直接拿下

C语言运算符优先级与数学思维的完美对应

1.算术运算符:与数学规则高度一致

C语言中的算术运算符优先级设计完全符合我们的数学常识:

  • 高级运算:乘法(*)、除法(/)和取模(%)具有相同的高优先级
  • 低级运算:加法(+)和减法(-)优先级较低

这种设计使得表达式a + b * c会先计算乘法后计算加法,与数学中的运算顺序完全一致,大大降低了学习成本。

2. 关系运算符:特殊注意相等性判断

在关系运算符中有一个需要特别注意的优先级规则:

  • 比较运算符>>=<<=具有较高优先级
  • 相等性判断==!=的优先级相对较低

这意味着表达式a > b == c < d实际上等价于(a > b) == (c < d),这种设计使得复合逻辑判断更加直观。

3.位运算与逻辑运算:严谨的优先级层次

位运算符和逻辑运算符的优先级设计体现了严谨的逻辑层次:

  1. "与"类运算优先级最高
    • 按位与&高于按位或|
    • 逻辑与&&高于逻辑或||
  2. 异或运算居中
    • 按位异或^的优先级介于按位与&和按位或|之间

这种层次分明的优先级设计使得位操作表达式能够准确表达开发者的意图,例如a & b ^ c | d会按照(a & b) ^ c) | d的顺序计算。

四、因不明确优先级而造成的常见问题

1、经典优先级陷阱案例

1. 指针解引用与自增的"暧昧关系"

int arr[] = {1, 2, 3};
int *p = arr;
int val = *p++;  // 你以为是什么?

问题分析

  • 很多人误以为等价于(*p)++,实际是*(p++)
  • 因为++优先级高于*,且是右结合

正确写法

(*p)++;  // 这才是解引用后自增

2. 位运算与比较运算的"优先级之争"

int flags = 0x0F;
if (flags & 0x0F == 0x0F) {  // 这个条件永远为假!printf("All bits set\n");
}

问题分析

  • ==优先级高于&,所以实际是flags & (0x0F == 0x0F)
  • (0x0F == 0x0F)结果为1,所以实际是flags & 1

正确写法

if ((flags & 0x0F) == 0x0F)

2、那些年我们踩过的优先级坑

1. 移位运算与算术运算的"爱恨情仇"

int x = 1 << 2 + 3;  // 你以为结果是32?其实是128!

解析

  • +优先级高于<<,所以是1 << (2 + 3) = 1 << 5 = 32
  • 但如果你想要(1 << 2) + 3 = 4 + 3 = 7,就需要加括号

2. 逻辑运算的"短路特性"引发的优先级误解

int a = 1, b = 0;
if (a == 1 || b == 1 && some_expensive_function()) {// 你以为some_expensive_function()不会执行?
}

解析

  • &&优先级高于||,所以等价于a == 1 || (b == 1 && some_expensive_function())
  • 由于a == 1为真,||短路,后面的确实不会执行
  • 但这样的代码可读性很差,建议加括号明确意图

3、防御性编程建议

  1. 多用括号:即使你知道优先级规则,加括号也能提高代码可读性

    // 不推荐
    a = b + c * d;// 推荐
    a = b + (c * d);
    
  2. 分解复杂表达式:将复杂表达式拆分成多个简单语句

    // 不推荐
    result = (*ptr++) + (x << 2) & mask;// 推荐
    int val = *ptr;
    ptr++;
    int shifted = x << 2;
    result = (val + shifted) & mask;
    
  3. 编写单元测试:对涉及复杂运算符的代码编写测试用例

4、常见优先级陷阱速查表

危险组合常见误解实际含义解决方案
*p++(*p)++*(p++)明确加括号
a & b == c(a & b) == ca & (b == c)加括号
a << b + c(a << b) + ca << (b + c)加括号
a = b = c从左到右赋值从右到左赋值保持原样或拆分

结语

运算符优先级就像交通规则,了解它们可以避免代码中的"交通事故"。记住:当你对优先级有哪怕一丝怀疑时,就加上括号吧!这不会降低你的专业度,反而会让你的代码更健壮、更易维护。

最后的小测试:你能一眼看出下面代码的问题吗?

int x = 5, y = 10, z = 15;
int result = x > y ? y : z + 10;

答案在评论区见!

http://www.lryc.cn/news/594632.html

相关文章:

  • 数据库的介绍和安装
  • HTTP,HTTPS
  • 文件的写出操作|文件的追加写入操作|文件操作的综合案例
  • mac安装node的步骤
  • IDEA 同时修改某个区域内所有相同变量名
  • 跑腿小程序|基于微信小程序的跑腿平台小程序设计与实现(源码+数据库+文档)
  • Taro 生命周期相关 API 详解
  • Idea或Pycharm上.idea的忽略提交的问题总结
  • Linux初识网络
  • 用 STM32 的 SYSTICK 定时器与端口复用重映射玩转嵌入式开发
  • 分布在内侧内嗅皮层(MEC)的带状细胞对NLP中的深层语义分析有什么积极的影响和启示
  • 微服务的编程测评系统-身份认证-管理员登录前端
  • .NET依赖注入IOC你了解吗?
  • 智能体性能优化:延迟、吞吐量与成本控制
  • 机器阅读理解(MRC)全面解析:任务分类、评估指标与57个数据集资源盘点
  • Nacos安装单例模式
  • 西门子 SIMATIC S7-1500 数字量输入模块:深度剖析与应用指南
  • ABQ-LLM:用于大语言模型的任意比特量化推理加速
  • Zabbix 企业级分布式监控系统深度解析
  • Android 单编 framework 相关产物输出介绍
  • 3.组合式API父子通信
  • OpenAI开发的一款实验性大型语言模型(LLM),在2025年国际数学奥林匹克竞赛(IMO)中达到了金牌水平
  • 什么是商业智能BI数据分析的指标爆炸?
  • 悬镜安全将受邀参加2025开放原子开源生态大会
  • “融合进化,智领未来”电科金仓引领数字化转型新纪元
  • FFmpeg:数字媒体的终极瑞士军刀
  • ssms(SQL 查询编辑器) 添加快捷键 Ctrl+D(功能等于Ctrl+C + Ctrl+V),一步到位
  • 【PTA数据结构 | C语言版】列出连通集
  • 第三章自定义检视面板_创建自定义编辑器类_如何自定义预览窗口(本章进度5/9)
  • C++基于libmodbus库实现modbus TCP/RTU通信