Skip to content

运算符(Operators)

运算符是对数据进行计算和比较的符号。C 语言提供了丰富的运算符,理解它们的优先级和结合性是写出正确表达式的关键。


1. 算术运算符

int a = 10, b = 3;

int sum    = a + b;    // 加 → 13
int diff   = a - b;    // 减 → 7
int prod   = a * b;    // 乘 → 30
int quot   = a / b;    // 除 → 3(整数除法,截断小数)
int remains = a % b;   // 取模(求余数)→ 1

整数除法 vs 浮点除法

int   x = 10 / 3;    // x = 3(整数除法)
float y = 10 / 3;    // y = 3.0(先做整数除法 10/3=3,再转为 3.0)

// 正确获取小数结果的方式:
float z1 = 10.0f / 3.0f;           // 直接用浮点数字面量
float z2 = (float)10 / 3;           // 将整数显式转换为浮点类型
float z3 = 10.0f / 3;               // 混合类型时自动提升

取模运算的特殊规则

  • 操作数必须都是整数,不能对 floatdouble 取模。
  • 结果的符号与被除数一致:
int r1 =  10 % 3;   // 1
int r2 = -10 % 3;   // -1(被除数为负,结果也为负)
int r3 =  10 % -3;  // 1(被除数为正,结果为正)

2. 关系运算符

关系运算符用于比较两个值,结果为 1(真)或 0(假)。

运算符 含义 示例(a = 10, b = 3
== 等于 a == b → 0
!= 不等于 a != b → 1
> 大于 a > b → 1
< 小于 a < b → 0
>= 大于等于 a >= 10 → 1
<= 小于等于 b <= 2 → 0

⚠️ 常见陷阱= 是赋值,== 是比较。if (x = 5) 永远为真——因为它把 5 赋给了 x,而 5 是非零值。正确写法是 if (x == 5)


3. 逻辑运算符

逻辑运算符连接多个条件,结果依然是 1(真)或 0(假)。

运算符 含义 示例
&& 逻辑与(AND) a > 0 && a < 100(a 在 0 到 100 之间)
|| 逻辑或(OR) x < 0 || x > 100(x 在范围外)
! 逻辑非(NOT) !flag(flag 为假时为真)

短路求值(Short-Circuit Evaluation)

// && 短路:左侧为假时,右侧不会执行
if (p != NULL && *p == 42) {  // 安全:p 为空时不会解引用
    // ...
}

// || 短路:左侧为真时,右侧不会执行
if (index < 0 || index >= size) {  // 任一条件满足即判定越界
    // ...
}

短路特性既提升效率,也常用于写"守卫条件"——先检查指针非空,再访问其内容。

逻辑运算真值表

A B A && B A || B !A
0 0 0 0 1
0 非0 0 1 1
非0 0 0 1 0
非0 非0 1 1 0

4. 位运算符

位运算符直接操作二进制位,常用于底层编程、标志位管理和性能优化。

运算符 含义 示例(a=5(0101), b=3(0011)
& 按位与 a & b → 1(0101 & 0011 = 0001)
\| 按位或 a \| b → 7(0101 | 0011 = 0111)
^ 按位异或 a ^ b → 6(0101 ^ 0011 = 0110)
~ 按位取反 ~a → -6(~00000101 = 11111010)
<< 左移 a << 1 → 10(0101 → 1010,乘 2)
>> 右移 a >> 1 → 2(0101 → 0010,除 2)

典型应用

// 1. 标志位操作(用一个整数的不同位表示多个开关)
#define FLAG_A  0x01    // 0001
#define FLAG_B  0x02    // 0010
#define FLAG_C  0x04    // 0100

int flags = 0;
flags |= FLAG_A;         // 打开 FLAG_A
flags &= ~FLAG_B;        // 关闭 FLAG_B
if (flags & FLAG_C) {    // 检测 FLAG_C 是否打开
    // ...
}

// 2. 高效率乘除 2 的幂
int x = 10;
int y = x << 3;   // 等价于 x * 8(前提是不溢出)
int z = x >> 2;   // 等价于 x / 4

⚠️ 不要混淆 &(按位与)和 &&(逻辑与)、|(按位或)和 ||(逻辑或)。前者操作每一位,后者操作布尔值并有短路特性。


5. 赋值运算符

int x = 10;

x += 5;    // x = x + 5  → 15
x -= 3;    // x = x - 3  → 12
x *= 2;    // x = x * 2  → 24
x /= 4;    // x = x / 4  → 6
x %= 4;    // x = x % 4  → 2

// 位运算的复合赋值
x <<= 2;   // x = x << 2
x &= 0x0F; // x = x & 0x0F

6. 自增与自减

int a = 5;
int b = ++a;    // 前置自增:a 先加 1,再赋值给 b → a=6, b=6
int c = a++;    // 后置自增:先赋值 a 给 c,a 再加 1 → c=6, a=7
写法 含义 执行顺序
++x 前置自增 先加后用
x++ 后置自增 先用后加
--x 前置自减 先减后用
x-- 后置自减 先用后减

建议:在复杂表达式中避免使用自增/自减(如 arr[i++] = ++j),拆成独立语句更清晰。


7. 条件运算符(三元运算符)

// 语法:条件 ? 为真时的值 : 为假时的值
int max = (a > b) ? a : b;

等价于:

int max;
if (a > b) {
    max = a;
} else {
    max = b;
}

三元运算符适合简单的二选一赋值。嵌套使用会严重降低可读性,应避免。


8. sizeof 运算符

printf("%zu\n", sizeof(int));      // 类型的大小
printf("%zu\n", sizeof(x));        // 变量的大小(可省略括号)
printf("%zu\n", sizeof(arr));      // 数组的总大小(元素数 × 每个元素大小)

9. 运算符优先级

当多个运算符同时出现时,优先级决定"谁先算"。优先级相同时,结合性决定方向。

优先级 运算符 结合性
1(最高) () [] -> . ++(后置) --(后置) 左到右
2 ! ~ ++(前置) --(前置) +(正) -(负) *(解引用) &(取地址) sizeof 右到左
3 * / % 左到右
4 + - 左到右
5 << >> 左到右
6 < <= > >= 左到右
7 == != 左到右
8 &(按位与) 左到右
9 ^ 左到右
10 \|(按位或) 左到右
11 && 左到右
12 \|\| 左到右
13 ?: 右到左
14 = += -= 等赋值符 右到左
15(最低) ,(逗号) 左到右

口诀:不确定优先级时,加括号。(a & mask) == maska & mask == mask 更安全、更清晰。


10. 总结

要点 说明
整数除法截断 需要小数结果时先将操作数转为浮点类型
== 不是 = 比较用 ==,赋值用 =
&&\|\| 短路 左侧结果能决定整体时右侧不执行
&\| 操作位 用于标志位和底层操作,不要与逻辑运算符混淆
优先级不确定时加括号 括号优先级最高,且让意图一目了然
避免复杂表达式中的 ++/-- 拆分语句可读性更好

作者: Qing | 修改日期: 2026-07-18