当前位置: 首页 > 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.dtcms.com/a/291086.html

相关文章:

  • 原型与原型链
  • 二维码扫描登录流程详解
  • 【Elasticsearch】settings
  • 解密分账系统:企业资金管理的智能中枢
  • Linux的相关指令
  • 京东商品评论如何获取?API接口实战指南
  • Kali MSF渗透Windows 11电脑
  • Linux_gdb调试器--进程概念
  • Linux初识网络
  • MySQL 核心知识点梳理(3)
  • buntu 22.04 上离线安装Docker 25.0.5(二)
  • 如何升级到macOS Tahoe:全面指南与实用步骤
  • LeetCode 每日一题 2025/7/14-2025/7/20
  • Mysql(存储过程)
  • 图像编辑开源数据项目
  • 了解 ReAct 框架:语言模型中推理与行动的协同
  • 疯狂星期四文案网第14天运营日记
  • DBSCAN聚类算法
  • OpenAI API(1)补全Responses(Chat Completions)API和记忆Assistants API对比分析
  • 牛客周赛 Round 101(题解的token计算, 76修地铁 ,76选数,76构造,qcjj寄快递,幂中幂plus)
  • 使用pymongo进行MongoDB的回收
  • JAVA高级第七章输入和输出处理(二)
  • 前缀和题目:元素和小于等于阈值的正方形的最大边长
  • PostgreSQL高可用架构Repmgr部署流程
  • 按需搭建web网站
  • 【2025】Vscode Python venv虚拟环境显示“激活终端”成功但是在终端中“并没有激活成功”,pip安装还是会安装到全局环境中的解决方法;
  • CataPro本地安装教程--No GPU--cpu only模式--网络资料整理
  • Android Navigation 组件:简化应用导航的利器
  • [硬件电路-67]:模拟器件 - 高输入阻抗、低输出阻抗本质:最小化能量的汲取,最大化能量传递
  • Dynamics 365 Contact Center是什么