首页 / C# 入门教程 / 运算符:算术、关系、逻辑、位运算与优先级

C# 入门教程

运算符:算术、关系、逻辑、位运算与优先级

本教程共 100 篇 · 第 15 篇 · 更新于 2026-07-31 · 约 10 分钟阅读

C#C# 入门教程编程语言运算符位运算优先级

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 / 102 而不是 2.1。想要小数,至少有一个操作数是 double(如 21 / 10.0)。

% 是取模(求余数),判断奇偶特别好用:n % 2 == 0 即为偶数。

为什么整数除法会丢小数

这是”类型决定结果类型”的体现:两个 int 相除,编译器自然也给 int,而整数没有小数部分,只能截断。这不是 bug,而是为了让结果类型可预测。若你写 21 / 10.0,因为 10.0double,结果就提升为 double,得到 2.1。记住一条:结果的类型,跟着操作数里”最宽”的那个走

自增与自减

++ 让变量加 1,-- 减 1。放在前面还是后面有区别:

int n = 5;
int x = n++;   // 先用后加:x=5,之后 n=6
int y = ++n;   // 先加后用:n 先变 7,y=7
Tip

初学不必纠结 ++nn++ 的差异,单独成行写 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(向下取整)。很多底层库、图像处理和权限系统用它提效。另一个常见用法是”标志位”:用每一位代表一个开关,多个权限用 | 合并、用 & 检测是否包含某权限。虽然初学用不到,但看懂别人的位操作代码时,知道它在”动二进制位”就够了。

五、运算符优先级:谁先算

表达式里运算符多时,优先级决定先后。记不住就加括号——这是最稳妥也最易读的做法。

精简优先级(从高到低):

  1. 括号 ()、下标 []、自增自减 ++ --
  2. 一元符号 +x -x、逻辑非 !、按位取反 ~
  3. * 、除 /、取模 %
  4. +、减 -
  5. 移位 << >>
  6. 关系 < > <= >=
  7. 相等 == !=
  8. 按位与 &、异或 ^、或 |
  9. 逻辑与 &&、逻辑或 ||
  10. 赋值 = 及复合赋值 +=

看一个经典例子:

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

数值类型、boolchar 这些值类型,== 永远比”值本身”,行为符合直觉,放心用。

优先级记不全怎么办

老实说,没人能背下完整优先级表。高手的做法是:不确定就加括号。括号既消除歧义,也让读代码的人一眼看懂你的意图。比起炫耀”我记得先算这个”,清晰的代码更值钱。

一个判断参考:当一行里混了算术、关系和逻辑三类运算符,基本就该加括号了。例如 (a + b) > c && da + b > c && d 更不容易误读。

常见疑问解答

问:% 取余对负数怎么算? 结果符号跟随被除数(左边的数)。如 -7 % 3-17 % -31。判断奇偶时用 n % 2 == 0,正负都不影响奇偶结论,可放心用。

问:自增 i++++i 在独立成行时有区别吗? 没有。单独写 i++;++i; 效果完全相同,都是让 i 加一。区别只在”作为表达式返回值”时:一个返回自增前、一个返回自增后。独立成行时挑顺手的即可。

问:逻辑运算符能用于非 bool 吗? 不能。&&||! 只认 bool。若你有整数想当真假用,必须先显式比较,如 if (count > 0),不能直接 if (count)。这是 C# 的安全设计。

要点速记

  • 算术:+ - * / %,整数相除取整。
  • 关系:> < >= <= == !=,结果都是 bool。
  • 逻辑:&& 且、|| 或、! 非;&&/|| 短路。
  • 优先级记不住就加括号;位运算玩二进制。

动手练一练

  1. 用取余 % 判断一个整数是奇数还是偶数,打印对应中文。
  2. bool a = true, b = false;,分别打印 a && ba || b!a,验证逻辑运算符行为。
  3. 故意写 (2 + 3) * 42 + 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)、逻辑管组合条件、位运算管二进制位。整数相除会截断,逻辑运算会短路,优先级拿不准就加括号。把这些记熟,写表达式就有了底气。

下一章我们讲赋值类运算符和空合并 ????=,它们是日常化简代码的利器。