> 一篇搞定C语言所有运算符:算术、关系、逻辑、位、赋值、三目、sizeof、优先级表全收录,附短路代码实验,写表达式不再懵!
一、算术运算符(整型&浮点通用)
| 运算符 | 功能 | 示例 | 备注 |
|---|---|---|---|
+ |
加/单目正 | a + b、+a |
单目很少写 |
- |
减/单目负 | a - b、-a |
常用 -a 取相反数 |
* |
乘 | a * b |
双目 |
/ |
除 | a / b |
整数相除舍去小数 |
% |
取模 | a % b |
两操作数必须整型 |
++ |
自增 | a++、 ++a |
前缀先加再用,后缀先用再加 |
-- |
自减 | a--、 --a |
同上 |
注意:
- 减号也是负号,比如
-a是取变量a的相反数 - 取模运算要求左右两边操作数必须是整型数据
- 自加和自减运算不仅可以对整型操作,也可以对浮点数、指针操作
- 前缀自加自减运算:先进行自加自减,再参与表达式运算
- 后缀自加自减运算:先参与表达式运算,再进行自加自减
① 整数除法陷阱
int a = 5, b = 2;
printf("%d\n", a / b); // 输出 2,不是 2.5
② 自增实验
int a = 100;
int b = 200;
int c = ++a; // a先自加1,变成101;然后再赋值给c,因此c等于101
int d = b++; // b先赋值给d,因此d等于200;然后b自加1,变成201float f = 3.14;
f++; // 浮点数也可以自增,f变成4.14int arr[5] = {1,2,3,4,5};
int *p = arr;
p++; // 指针自增,指向下一个元素
二、关系运算符(结果 0 或 1)
| 运算符 | 功能 | 示例 | 数学含义 |
|---|---|---|---|
> |
大于 | a > b |
⩾ 不成立 |
>= |
大于等于 | a >= b |
⩾ 成立 |
< |
小于 | a < b |
< 成立 |
<= |
小于等于 | a <= b |
≤ 成立 |
== |
相等 | a == b |
≠ 请用 != |
!= |
不相等 | a != b |
≠ |
关系表达式值:真=1,假=0
注意:
- 关系运算符用于判断运算符两边的表达式是否满足给定的大小条件。
- 由关系运算符组成的表达式称为关系表达式,其值为布尔型(非零则真)。
- 判断是否相等是双等号==,而不是一个等号(赋值)。
三、逻辑运算符(短路特性)
| 运算符 | 功能 | 示例 | 短路规则 |
|---|---|---|---|
! |
逻辑非 | !a |
单目,真假翻转 |
&& |
逻辑与 | a && b |
左假右不算 |
|| |
逻辑或 | a || b |
左真右不算 |
-
短路实验
int a = 0, b = 1;
int x = (a && ++b); // b 不会自增,因为左边已假
printf("b = %d\n", b); // 输出 1
四、位运算符(直接操作二进制)
| 运算符 | 名称 | 举例 | 功能说明 |
|---|---|---|---|
~ |
位逻辑反(单目运算符) | ~a |
将变量 a 中的每一位取反 |
& |
位逻辑与(双目运算符) | a & b |
将变量 a 和 b 逐位进行与操作 |
| |
位逻辑或(双目运算符) | a | b |
将变量 a 和 b 逐位进行或操作 |
^ |
位逻辑异或(双目运算符) | a ^ b |
将变量 a 和 b 逐位进行异或操作 |
<< |
左移 | a << 4 |
将变量 a 中的每一位向左移动4位 |
>> |
右移 | a >> 4 |
将变量 a 中的每一位向右移动4位 |
重要说明
- 位运算符操作的对象是数据中的每一位(
int需要操作32个二进制位,short需要操作16个二进制位...) - 运算规则:
- 位逻辑反、位逻辑与(有0得0)、位逻辑或(有1得1)拥有与逻辑运算相似的规则和一样的真值表
- 异或运算:相同为0,不同为1
- 移位运算:移出去的不要,空出来补(左移则补0,右移则补符号位)
示例代码
① 快速置位/清位
#include <stdio.h>
#include <stdint.h>int main(void)
{uint8_t a = 0b10101010; // 170uint8_t b = 0b11001100; // 204printf("a & b = 0x%02X\n", a & b); // 0x88 (0b10001000)printf("a | b = 0x%02X\n", a | b); // 0xEE (0b11101110)printf("a ^ b = 0x%02X\n", a ^ b); // 0x66 (0b01100110)printf("~a = 0x%02X\n", ~a); // 0x55 (0b01010101)printf("a << 2 = 0x%02X\n", a << 2); // 0xA8 (0b10101000)printf("a >> 2 = 0x%02X\n", a >> 2); // 0x2A (0b00101010)return 0;
}
② 交换两变量(无临时)
a ^= b;
b ^= a;
a ^= b;
五、赋值 & 复合赋值
赋值运算符
重要规则
- 不能对常量赋值,只能对变量赋值
- 不能对数组赋值(因为数组名字表示的是一个数据的地址)
- 可以连续赋值,顺序从右到左
// 正确示例
int a, b, c;
a = b = c = 10; // 连续赋值,等价于 c=10; b=c; a=b;// 错误示例
5 = a; // ❌ 不能对常量赋值
int arr[5];
arr = {1,2,3}; // ❌ 不能对数组名赋值
复合赋值符说明
- 当赋值符号左右两边有相同的操作数时,采用复合赋值符不仅直观,且能提高运算效率
- 除了以下10个复合运算符之外,生造别的复合运算符是非法的
| 简单形式 | 复合形式 | 等价写法 |
|---|---|---|
a = a + b |
a += b |
语义相同,复合更简洁 |
a = a - b |
a -= b |
—— |
a = a * b |
a *= b |
—— |
a = a / b |
a /= b |
—— |
a = a % b |
a %= b |
—— |
a = a & b |
a &= b |
位运算同样适用 |
a = a | b |
a |= b |
—— |
a = a ^ b |
a ^= b |
—— |
a = a << n |
a <<= n |
—— |
a = a >> n |
a >>= n |
—— |
六、三目运算符(唯一三元)
- 唯一需要三个操作数的运算符
- 语法:表达式1 ? 表达式2 : 表达式3
- 释义:当表达式1为真时,取表达式2,否则取表达式3
int m = (a > b) ? a : b; // 取较大值
//等价于
int m;
if (a > b) m = a;
else m = b;
七、sizeof 与 return
sizeof 运算符
- 含义:计算指定数据类型或者变量所占据内存的字节数(多大)
- 语法:sizeof(类型) 、sizeof(变量名) ,计算变量的字节数时圆括号可以省略(一般会保留)
举例
printf("%d\n", sizeof(int));
printf("%d\n", sizeof(long double));int a[5];
printf("%d\n", sizeof(a));
printf("%d\n", sizeof a );
return运算符
- 含义:退出某个函数(如果退出的是主函数main,那么整个程序也就退出了)
- 语法:必须出现在函数体内,可以带函数对应类型的数据
举例
int main()
{return 0;//说明:return 用于函数返回;main 函数返回 0 表示成功。
}char func()
{return 'H';
}
八、运算符优先级 & 结合性(速查表)
| 优先级 | 运算符 | 结合方向 | 记忆口诀 |
|---|---|---|---|
| 1 | () [] -> . |
左→右 | 括号下标成员 |
| 2 | ! ~ ++ -- + - * & sizeof |
右→左 | 单目 |
| 3 | * / % |
左→右 | 乘除模 |
| 4 | + - |
左→右 | 加减 |
| 5 | << >> |
左→右 | 移位 |
| 6 | < <= > >= |
左→右 | 关系 |
| 7 | == != |
左→右 | 相等 |
| 8 | & |
左→右 | 按位与 |
| 9 | ^ |
左→右 | 按位异或 |
| 10 | | |
左→右 | 按位或 |
| 11 | && |
左→右 | 逻辑与 |
| 12 | || |
左→右 | 逻辑或 |
| 13 | ?: |
右→左 | 三目 |
| 14 | = += -= 等 |
右→左 | 赋值 |
| 15 | , |
左→右 | 逗号 |
实操建议:不确定就加括号,比背表更靠谱!
综合示例
int x = 5, y = 4, z;
z = x + y * 2 >> 1 & 3; // 等价于:z = ((x + (y * 2)) >> 1) & 3;
printf("%d\n", z); // 输出 1