运算符:算术、关系、逻辑、位运算与优先级
本教程共 100 篇 · 第 15 篇 · 更新于 2026-07-31 · 约 10 分钟阅读
15. 运算符:算术、关系、逻辑、位运算与优先级
本节目标:学完能正确写出算术、比较、逻辑和位运算表达式,并理解整数除法、短路求值与优先级规则。
运算符是「告诉编译器做什么运算」的符号。C# 的运算符很多,本章聚焦最常用的四类:算术、关系、逻辑、位运算,最后给出一份够用的优先级速查表。
一、算术运算符:加减乘除那些事
最基础的一组:+ - * / %,以及自增 ++、自减 --。
int a = 21, b = 10;
Console.WriteLine(a + b); // 31
Console.WriteLine(a - b); // 11
Console.WriteLine(a * b); // 210
Console.WriteLine(a / b); // 2
Console.WriteLine(a % b); // 1,取余数
Note一个高频坑:两个整数相除,结果还是整数,小数部分直接舍去。所以
21 / 10得2而不是2.1。想要小数,至少有一个操作数是double(如21 / 10.0)。
% 是取模(求余数),判断奇偶特别好用:n % 2 == 0 即为偶数。
为什么整数除法会丢小数
这是”类型决定结果类型”的体现:两个 int 相除,编译器自然也给 int,而整数没有小数部分,只能截断。这不是 bug,而是为了让结果类型可预测。若你写 21 / 10.0,因为 10.0 是 double,结果就提升为 double,得到 2.1。记住一条:结果的类型,跟着操作数里”最宽”的那个走。
自增与自减
++ 让变量加 1,-- 减 1。放在前面还是后面有区别:
int n = 5;
int x = n++; // 先用后加:x=5,之后 n=6
int y = ++n; // 先加后用:n 先变 7,y=7
Tip初学不必纠结
++n和n++的差异,单独成行写n++;最不容易出错;只有在同一表达式里混用时才需要分前后。
二、关系与相等运算符:结果是 bool
这类运算符比较两个值,结果都是 bool(第 11 章讲过)。
| 运算符 | 含义 |
|---|---|
== | 等于 |
!= | 不等于 |
> < | 大于 / 小于 |
>= <= | 大于等于 / 小于等于 |
int score = 85;
Console.WriteLine(score > 60); // True
Console.WriteLine(score == 100); // False
Note字符串也能用
==比内容(见第 14 章)。但引用类型默认比的是「地址」,别把==当成万能等号;自定义类要正确比较需要实现自己的逻辑。
三、逻辑运算符:把多个条件合起来
逻辑运算符操作 bool,得到 bool。常见三个:
&&逻辑与:两边都为真,结果才真。||逻辑或:只要一边真,结果就真。!逻辑非:取反,真变假、假变真。
bool hasTicket = true;
bool isAdult = true;
bool canEnter = hasTicket && isAdult; // 两个都真
Console.WriteLine(canEnter); // True
bool vip = false;
bool freeEntry = canEnter || vip; // 一边真即可
Console.WriteLine(freeEntry); // True
Console.WriteLine(!vip); // True,VIP 取反
短路求值:省时又安全
&& 和 || 有「短路」特性:左边已经能决定结果时,右边不再计算。
int n = 0;
bool result = n != 0 && (10 / n > 1); // 左边为假,右边被跳过,不会除零
Console.WriteLine(result);
这不仅是性能优化,更是安全屏障:上面这种写法避免了「除零异常」。把「可能为假的防护条件」放 && 左边,是常见好习惯。
Tip利用短路,可以把”前置检查”放在
&&左边护着右边的危险操作。比如index >= 0 && arr[index] > 0,若index越界,右边的访问根本不会执行,自然不会崩。这是写安全代码的小技巧。
四、位运算:在二进制位上操作
位运算符直接操作整数在内存里的二进制位,常用于底层、权限标志、加密等场景。不必精通,但要知道它们存在。
| 运算符 | 含义 | 示例(二进制) |
|---|---|---|
& | 按位与 | 同 1 得 1 |
| | 按位或 | 有 1 得 1 |
^ | 按位异或 | 不同得 1 |
~ | 按位取反 | 0 变 1、1 变 0 |
<< >> | 左移 / 右移 | 位整体平移 |
int p = 60; // 二进制 0011 1100
int q = 13; // 二进制 0000 1101
Console.WriteLine(p & q); // 12,0000 1100
Console.WriteLine(p | q); // 61,0011 1101
Console.WriteLine(p ^ q); // 49,0011 0001
Console.WriteLine(p << 2); // 240,左移两位相当于乘 4
Tip
^异或有个有趣性质:a ^ b ^ b == a,因此常用来做简单的「无临时变量交换」或轻量加密。日常业务代码用得少,了解即可。
位运算的实用直觉
左移 << 一位相当于乘 2,右移 >> 一位相当于除以 2(向下取整)。很多底层库、图像处理和权限系统用它提效。另一个常见用法是”标志位”:用每一位代表一个开关,多个权限用 | 合并、用 & 检测是否包含某权限。虽然初学用不到,但看懂别人的位操作代码时,知道它在”动二进制位”就够了。
五、运算符优先级:谁先算
表达式里运算符多时,优先级决定先后。记不住就加括号——这是最稳妥也最易读的做法。
精简优先级(从高到低):
- 括号
()、下标[]、自增自减++-- - 一元符号
+x-x、逻辑非!、按位取反~ - 乘
*、除/、取模% - 加
+、减- - 移位
<<>> - 关系
<><=>= - 相等
==!= - 按位与
&、异或^、或| - 逻辑与
&&、逻辑或|| - 赋值
=及复合赋值+=等
看一个经典例子:
int r = 2 + 3 * 4; // 先乘后加,得 14
int s = (2 + 3) * 4; // 括号改变顺序,得 20
逻辑运算里,&& 高于 ||,所以 a || b && c 等价于 a || (b && c)。但强烈建议用括号写清楚,别考验读者的脑回路。
Note优先级表不用背全。原则是:乘除先于加减,比较先于逻辑,赋值优先级最低;任何拿不准的组合,一律加括号。括号既消除歧义,也让三个月后的你感谢现在的自己。
比较相等也用 == 吗
第 11 章提过,string 用 == 比较的是”内容”而非”地址”,这点很贴心。但其他引用类型(比如你自己写的 class)默认 == 比的还是”是不是同一个对象”,不是内容。要让自定义类型也比内容,需要重写相等逻辑(第 47 章讲 object 基类时会涉及)。
所以默认规则是:字符串 == 比内容,其他引用类型 == 比引用。别想当然套用。
Note数值类型、
bool、char这些值类型,==永远比”值本身”,行为符合直觉,放心用。
优先级记不全怎么办
老实说,没人能背下完整优先级表。高手的做法是:不确定就加括号。括号既消除歧义,也让读代码的人一眼看懂你的意图。比起炫耀”我记得先算这个”,清晰的代码更值钱。
一个判断参考:当一行里混了算术、关系和逻辑三类运算符,基本就该加括号了。例如 (a + b) > c && d 比 a + b > c && d 更不容易误读。
常见疑问解答
问:% 取余对负数怎么算?
结果符号跟随被除数(左边的数)。如 -7 % 3 得 -1,7 % -3 得 1。判断奇偶时用 n % 2 == 0,正负都不影响奇偶结论,可放心用。
问:自增 i++ 和 ++i 在独立成行时有区别吗?
没有。单独写 i++; 和 ++i; 效果完全相同,都是让 i 加一。区别只在”作为表达式返回值”时:一个返回自增前、一个返回自增后。独立成行时挑顺手的即可。
问:逻辑运算符能用于非 bool 吗?
不能。&&、||、! 只认 bool。若你有整数想当真假用,必须先显式比较,如 if (count > 0),不能直接 if (count)。这是 C# 的安全设计。
要点速记
- 算术:
+ - * / %,整数相除取整。 - 关系:
> < >= <= == !=,结果都是 bool。 - 逻辑:
&&且、||或、!非;&&/||短路。 - 优先级记不住就加括号;位运算玩二进制。
动手练一练
- 用取余
%判断一个整数是奇数还是偶数,打印对应中文。 - 写
bool a = true, b = false;,分别打印a && b、a || b、!a,验证逻辑运算符行为。 - 故意写
(2 + 3) * 4和2 + 3 * 4,对比结果,体会括号对优先级的影响。
整数除法与小数除法的对比
这一节单列出来,因为踩的人实在太多。关键看操作数类型:
Console.WriteLine(21 / 10); // 2,两个 int,结果 int,截断
Console.WriteLine(21 / 10.0); // 2.1,有 double,结果 double
Console.WriteLine(21.0 / 10); // 2.1,同样升级为 double
要得到带小数的商,牢记”至少一个操作数是浮点(double/decimal/float)“。涉及金额务必用 decimal,别用 double,否则有精度误差。
短路求值的另一面
短路好用,但有个副作用:被跳过的一边”不会执行”。如果那一边有副作用(比如调用一个会修改状态的方法),跳过它就跳过了副作用,逻辑可能和你预期不同。
bool ok = false;
bool r = ok && DoSomething(); // ok 为假,DoSomething 不会被调用
所以把”有副作用的调用”放在短路的右边要当心——它可能在你以为会执行时根本没执行。需要时拆成独立 if,反而更清晰可控。
小结与下一步
四类基础运算符:算术管计算、关系管比较(出 bool)、逻辑管组合条件、位运算管二进制位。整数相除会截断,逻辑运算会短路,优先级拿不准就加括号。把这些记熟,写表达式就有了底气。
下一章我们讲赋值类运算符和空合并 ??、??=,它们是日常化简代码的利器。