逻辑运算的C程序实现

官方信息技术老师·10 页·深入(追求细节与边界)·0 次浏览·3 天前
短路求值位运算求值顺序副作用

逻辑运算的C程序实现

看清短路求值的执行机理,分清位运算与逻辑运算的边界,掌握副作用与求值顺序的所有坑

按 空格/→ 演示下一步

1 / 10 页

全部页面点击任意一页,跳回舞台从这页播放

短路求值位运算求值顺序副作用

逻辑运算的C程序实现

看清短路求值的执行机理,分清位运算与逻辑运算的边界,掌握副作用与求值顺序的所有坑

1第 1 页 · 逻辑运算的C程序实现

逻辑运算问题~1

上一页讲清了 &&、||、! 的写法,但「会写」不等于「写对」。C 语言的逻辑运算有几个隐藏规则——短路求值、结果类型、优先级——正是 bug 的高发地。

短路求值
左操作数已能确定结果时,右操作数整个被跳过,不执行
结果总是 0/1
不像 Python 返回最后操作数,永远返回 int 类型的 0 或 1
优先级陷阱
! > 算术 > 关系 > && > || > 赋值,复杂式必须加括号
副作用可能丢失
短路时右边的自增、函数调用、赋值可能根本不执行
简历初筛对应 →短路求值

学历不达标直接淘汰,后面「项目经验」「面试表现」这些关卡都不用再看了

2第 2 页 · 逻辑运算问题~1

逻辑运算表达式

上页我们看懂了 `&&`、`||`、`!` 在 C 里怎么写,但这三个运算符一旦组合成表达式,规则就复杂起来——尤其涉及求值顺序、返回类型和优先级。本页聚焦这些容易写错、调试时又难发现的细节。

三个逻辑运算符
分双目与单目;操作数无类型限制,整型、浮点、指针都行
短路求值
左操作数已能定结果时,右操作数及其副作用不再执行
结果归 0 或 1
不论操作数是整数、浮点还是指针,最终返回整数 0 或 1
优先级与结合性
! 最高,关系运算次之,&& 再低,|| 最低;同级左结合
过安检门对应 →短路求值

第一道门就报警(已定结果),后面几道不再检(右侧不执行)

3第 3 页 · 逻辑运算表达式

如何判断闰年

上页我们用&&、||把多个布尔条件拼成一个表达式。判断闰年正是它的经典案例——要把整除判断和百年例外复合在同一条表达式里。

公历闰年规则
能被4整除;若该年是整百年,还必须能被400整除
取模判整除
year % n == 0 等价于 year 能被 n 整除
逻辑组合
百年例外单独用括号包,避免和别的||混淆
边界用例
1900不是闰年(整百不整400),2000是闰年(整百又整400)
优惠门槛规则对应 →闰年判定

基础折扣看年限(%4==0);百年店庆必须满400年才打折

(year%4==0&&year%100!=0)(year%400==0)(year \% 4 == 0 \&\& year \% 100 != 0) \|\| (year \% 400 == 0)
4第 4 页 · 如何判断闰年

逻辑运算优先级

闰年那行 `year%4==0 && year%100!=0 || year%400==0`,C 编译器不是从左到右一扫而过——它按优先级分层读取。读错层,判断就错位。

优先级层次
! 最高,&& 次之,|| 最低
短路求值
结果已定即停:&& 遇假停,|| 遇真停
位运算之别
& 和 | 不短路,优先级也低于关系运算
善用括号
含混时显式加括号,免去背表的负担
先乘除后加减对应 →C 逻辑运算优先级

先算谁有规则,写代码与写算式一样要分层思考

a\,||\,b\,&&\,!c\;\equiv\;a\,||\,(b\,&&\,(!c))
5第 5 页 · 逻辑运算优先级

条件运算符

闰年判断里我们写 if-else 做分支。表达式层面的「二选一」有专用写法——C 里唯一一个三目运算符:条件运算符 ?:。

唯一三目运算符
C 里唯一带三个操作数的运算符:expr1 ? expr2 : expr3
短路求值有保证
expr1 为真只算 expr2,为假只算 expr3;C 标准明确保证,另一个表达式不会求值
类型按隐式转换确定
两分支类型不同则按寻常算术转换逐次统一,结果类型与 if-else 同位置变量完全一致
优先级低且右结合
低于算术、关系、逻辑运算符;嵌套时从右往左结合,复杂场景建议补括号
岔路口看指示牌选路对应 →条件运算符 ? :

指示牌(条件)指左(分支1)或右(分支2);只走其中一条,绝不会两条都走

6第 6 页 · 条件运算符

计算结合性

上一页学了条件运算符 `?:`,但如果一行出现两个相同符号(`a=b=c=5` 或两个 `?:` 嵌套),谁先谁后?这就是结合性要回答的问题——同优先级运算符的分组方向。

结合性的定义
优先级相同的运算符连用时,决定它们如何「两两配对」的规则
左结合(绝大多数)
+ - * / % 和 && || 等双目运算符,从左往右依次结合
右结合(少数派)
赋值 =、复合赋值(+= -= 等)、条件 ?: 从右往左结合
链式赋值
a=b=c=5 等价于 a=(b=(c=5)),值 5 被依次赋到 c、b、a
穿衣服与套盒子对应 →左结合与右结合

左结合像穿衣(先袜后鞋,固定从左到右);右结合像套盒(先内后外,从右到左组装)

abc((ab)c),a=b=ca=(b=c)a-b-c \equiv ((a-b)-c), \quad a=b=c \equiv a=(b=c)
7第 7 页 · 计算结合性

一个简单实例

前面把结合性、优先级、短路规则都过了一遍,不如拿一个真实小例子把 &&、! 串在一起,一眼看清整套规则怎么落到代码里。

应用场景
用户登录:年满18岁、有账号、且未被封禁,三条同时成立才放行
表达式写法
age >= 18 && has_account && !banned
短路求值
第一条为假时,后面的子条件不再被求值
优先级体会
! 最先,再 &&;不确定顺序时直接加括号最稳
小区门禁刷卡对应 →复合逻辑判断

年龄够 + 卡有效 + 未被拉黑,三样都齐才能放行

8第 8 页 · 一个简单实例

本节要点

  • && 和 || 有短路特性,一遇确定结果即停
  • 逻辑运算优先级:! > 算术 > 关系 > && > ||
  • 逻辑运算符求真假,按位运算符逐位处理
  • 条件运算符适合简化单值赋值,比 if-else 紧凑
  • 复杂判断先拆条件再组合,括号标注优先级
延伸主题:短路求值的副作用与陷阱德摩根定律化简布尔表达式
9第 9 页 · 本节要点

课后思考

先自己想一分钟,再点开参考答案看思路。

1&& 和 || 都有短路特性。请举两个真实场景,说明把可能崩溃的调用放在右侧为什么更安全。

参考答案例 1:if(p && *p),p 为 NULL 时跳过解引用,避免段错误;例 2:if(d && a/d),d 为 0 时跳过除法,避免崩溃。短路把右侧危险代码拦在左侧为假的门外。

2把判断「正偶数」的表达式 (x>0 && x%2==0) 误写成 ||,哪些输入会蒙混过关?举两个例子。

参考答案负偶数(如 -2)和 0 会蒙混过关。|| 只需「能被 2 整除」一项为真就放行,不再要求 x>0,于是负偶数和零都被错误判定为正偶数。

3把闰年判断式 (year%4==0 && year%100!=0) || year%400==0 套到负数年份,结果还可靠吗?为什么?

参考答案不完全可靠。C 标准中 % 对负数取模的结果由实现定义,同一个负年份在不同编译器下可能得出不同余数,公式可能判错。需先取绝对值或限定年份范围。

10第 10 页 · 课后思考