news 2026/7/14 4:50:12

运算符与表达式

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
运算符与表达式

目录

1.运算符

2.表达式

3.运算符的分类

3.1 算术运算符

++(自增运算符)

– – (自减运算符)

3.2 关系运算符

3.3 逻辑运算符

C语言逻辑运算符是 "惰性运算"

3.4 位运算符

1.~ 按位取反

2. & 按位与

3. | 按位或

4. ^ 按位异或

有两个变量 a,b 要交换a和b的值 不适用其他临时变量

5. << 按位左移

6. >> 按位右移

7.掩码(mask)

8.总结

3.5 赋值运算符

赋值表达式的值:就是赋值完之后 左边那个操作数的值

3.6 条件运算符

? : 三目运算符

3.7 逗号运算符

3.8 指针运算符

3.9 求字节运算符

3.10 分量运算符

3.11 下标运算符

3.12 强制类型转换

4.运算符的优先级和结合性


1.运算符

什么是运算符

运算符是用来表示某种运算(操作)的符号

如:+ - * / % 等

根据运算符需要带几个操作数(运算符) 分为

> 单目运算符:该运算符只需要一个操作数 如 : ++ - - &(取地址符) 等

> 双目运算符:该运算符需要两个操作数 如 :+ - * / % 等

> 三目运算符:该运算符需要三个操作数 如: **? :**

结合性:决定先算哪个操作数的问题

从左至右结合 从右至左结合

举个例子

在C语言中 已知 + 的结合性 从左至右

a + b 和 b + a 在C语言中含义不一样的

运算符的优先级

> 在含有多个运算符的表达式中 决定先算哪个运算符 后算哪个运算符

> 如: a + b*c

单目运算符 > 算术运算符 > 关系运算符 > 逻辑运算符 > 赋值运算符 > 逗号运算符

2.表达式

什么是表达式

> 表达某个意思的式子

> C语言中的表达式一般来说是用 运算符连接操作数的式子 如: 3 + 5

表达式的值

> 是一个表达式 就一定会有一个值 这个值就是表达式的值

> 表达式最终需要表达某个意思 某个意思就是表达式的值 3.运算符的分类

3.运算符的分类

3.1 算术运算符

进行算术运算的运算符

++ -- 单目运算符

* / % 双目运算符

+ - 双目运算符

+ - * / 只需要操作数是一个数(整数可以 浮点数可以)

% 取余 要求两个操作数必须是 整数

如:

3 + 4

3.5 + 4.7

3.5 * 6

3.3 / 2

5 % 3

3 % 3.3 error

4 / 2 => 2

5 / 2 => 2

5 / 3 => 1

5 / 2.0 => 2.5

(double)(3/2) => 1.0

(double)3 / 2 => 1.5

++(自增运算符)

自增(+1) 运算符 单目运算符 要求操作必须为一个左值(lvalue)

在C语言中 只有变量才具备左值

  • 前置++: ++在前面 ++x
  • 后置++: ++在后面 x++```

– – (自减运算符)

自减(+1) 运算符 单目运算符 要求操作必须为一个左值(lvalue)

在C语言中 只有变量才具备左值

  • 前置- -: - - 在前面 - - x
  • 后置- -: - -在后面 x- -

表达式的值 做完表达式之后 i 的值

i++ i i = i + 1

++i i+1 i = i + 1

i-- i i = i - 1

--i i-1 i = i - 1

例子: int i = 5; int j = 6; int a; a = (i++) + (i+j);//a=17 或 a = (i+j) + (i++);//a=16

3.2 关系运算符

用来判断两个东西的 关系的运算符 关系:数值大小关系 "比 数值大小"

双目运算符 结合性 从左至右

> < >= <= ==(等于) != (不等于)

关系表达式: 用关系运算符连接起来的表达式 如 a > b

关系表达式的值

  • ​ 关系成立
  • ​ 关系不成立 0

如:

5 > 3 表达式的值是 1

5 > 7 表达式的值是 0

5 >= 5 表达式的值是 1

5 > 4 > 3 表达式的值为 0

结合型 从左至右

==> (5>4) > 3

==> 1 > 3

==> 0

5 > 4 > 3 是一个合法的表达式 是拿 5 > 4 的值 和 3 进行比较

在C语言中 5 > 4 > 3 这个表达式和数学上 "5 > 4 > 3" 的含义是不一样的

(1) C语言中 5 > 4 > 3 <===> (5 > 4) > 3

(2) 数学上 5 > 4 >3 是 "5 > 4" 并且 "4 > 3"

3.3 逻辑运算符

! 逻辑非 单目运算符 "取反"

&& 逻辑与 双目运算符 "并且" 从左至右

|| 逻辑或 双目运算符 "或者" 从左至右

逻辑表达式:用逻辑运算符 (! && ||) 连接起来的式子 称为 逻辑表达式

逻辑表达式的值

  • ​ 真:1
  • ​ 假:0

但是非0 也是逻辑真

a b a&&b a||b

真 真 真 真

真 假 假 真

假 真 假 真

假 假 假 假

例子 int a = 4; int b = 5; a && b ==> 1 a || b ==> 1 !a && b ==> 假 && 真 ==> 0

注意优先级

5 > 3 && 8 < 4 - !0

5 > 3 && 8 < 4 - 1

5 > 3 && 8 < 3

1 && 0 ==> 真 && 假 ==> 假 ==> 所以表达式的值 0

练习

1. 分析如下程序的输出结果 #include <stdio.h> int main() { int a,b,c,d,m,n; a = 1; b = 2; c = 3; d = 4; m = 1; n = 1; (m = a > b) && (n = c > d); printf("%d %d %d %d %d %d\n",a,b,c,d,m,n);//1 2 3 4 0 1 }

C语言逻辑运算符是"惰性运算"

a && b && c

只有当a为真 才需要判断b的值

只有当 a b 都为真 才需要判断 c的值

a || b || c

只要a的值为真 就不需要判断b和c的值

只有 a 和 b都为假 才需要判断 c 的值

总之 如果实现知道了表达式的值啦 那么后面的运算符或表达式就不执行了

练习:

2. 分析如下程序的输出结果 注:&& 的优先级比 || 高 提示:考虑运算符的结合性(从左至右) //优先级不等于求值顺序 优先级只是为了确保正确的分组 求值一定是从左往右 //(group) || (c = c - 1) int a = 0,b = 1,c = 1; int d = a && (b = b - 1) || (c = c - 1); printf("%d %d %d %d\n",a,b,c,d);//0 1 0 0 /* ( a && (b = b - 1) ) || (c = c - 1) x || y 0 || 0 */ //a || (group) int a = 1,b = 1,c = 1; int d = a || (b = b - 1) && (c = c - 1); printf("%d %d %d %d\n",a,b,c,d);//1 1 1 1 /* a || ( (b = b - 1) && (c = c - 1) ) x || y x为1 所以y式子 不执行 */ int a = 0,b = 1,c = 1; int d = a || (b = b - 1) && (c = c - 1); printf("%d %d %d %d\n",a,b,c,d);//0 0 1 0 /* a || ( (b = b - 1) && (c = c - 1) ) x || y x为0 所以y的值会影响整个式子的值 当y为0 整个式子为0 当y为1 整个式子为1 所以 y需要执行 0 || 0 */

3.4 位运算符

位运算符 是 按bit位展开来进行的运算 意思就是说 操作数会展开为 bit位 然后再进行运算

位运算符要求 操作数必须为整数

~ 按位取反

& 按位与

| 按位或

^ 按位异或

<< 按位左移

>> 按位右移

除了 ~(按位取反) 是单目运算符之外 其他所有的都是双目运算符 结合性 从左至右

1.~ 按位取反

1 -> 0 0 -> 1 !3 逻辑非 ==> 0 ~3 (假设 int 占 32bits) 00000000 00000000 00000000 0000 0011 11111111 11111111 11111111 1111 1100 <-- ~3

NOTE:

> 按位取反 ~ 和 逻辑非 !

> 都是单目运算符

  • !x 对于x没有要求
  • ~x 要求x 是整数

练习:

1.分析如下程序的输出结果 #include <stdio.h> int main() { int a = ~(-3); printf("%d\n",a);// 2 printf("%u\n",a);// 2 /* |-3|的原码: 00000000 00000000 00000000 0000 0011 11111111 11111111 11111111 1111 1100 取反 补码: 11111111 11111111 11111111 1111 1101 +1 <-- -3在计算机中的存放形式 ∴ ~(-3) 00000000 00000000 00000000 0000 0010 */ int b = !(-3); printf("%d\n",b);// 0 printf("%u\n",b);// 0 }

2. & 按位与

a & b 双目运算符 结合性:从左至右

aba & b
111
100
010
000

例子:假设int 占 32bits

3 & 5 == 1

00000000 00000000 00000000 0000 0011

& 00000000 00000000 00000000 0000 0101

00000000 00000000 00000000 0000 0001

3 & 7 == 3

00000000 00000000 00000000 0000 0011

& 00000000 00000000 00000000 0000 0111

00000000 00000000 00000000 0000 0011

练习

1.假设有一个整型变量a 我要把a的bit5 变为0 其他bit位保持不变 该如何操作

a = a & 0xFFFFFFDF;

a = a & ~(1<<5) ;

结论:

  • 一个bit位 与 0 进行 "按位与&" 操作 结果为0
  • 一个bit为 与 1 进行 "按位与&" 操作 结果 保留原值

3. | 按位或

a | b 双目运算符 结合性 从左往右

aba|b
111
101
011
000

例子:假设int占 32bits

3 | 5 == 7

00000000 00000000 00000000 0000 0011

| 00000000 00000000 00000000 0000 0101

00000000 00000000 00000000 0000 0111

3 | 7 == 7

00000000 00000000 00000000 0000 0011

| 00000000 00000000 00000000 0000 0111

00000000 00000000 00000000 0000 0111

练习:

1.假设有一个整型变量a 我要把a的bit5 置1 其他bit位保存不变 该如何操作

a = a | 0x00000020;

a = a | (1<<5);

结论

  • 一个bit位 与 1进行 "按位或|"操作 结果为1
  • 一个bit为 与 0进行 "按位或|"操作 结果 保留原值

4. ^ 按位异或

异或:求异 不同为1 相同为0

aba^b
110
101
011
000

例子:假设int占32bits

2^32 == 34

00000000 00000000 00000000 0000 0010

^ 00000000 00000000 00000000 0010 0000

00000000 00000000 00000000 0010 0010

3 ^ 7 == 4

00000000 00000000 00000000 0000 0011

^ 00000000 00000000 00000000 0000 0111

00000000 00000000 00000000 0000 0100

练习

1.假设有一个整型变量a 我要把a的bit5 保持不变 其他位取反 该如何操作

a = a ^ 0xFFFFFFDF;

a = a ^ ~(1<<5);

结论

  • 一个bit位 与0进行 "按位异或"操作 结果保留原值
  • 一个bit位 与1进行 "按位异或"操作 结果 取反
有两个变量 a,b 要交换a和b的值 不使用其他临时变量

> 异或可以实现

a = a ^ b;

b = a ^ b;

a = a ^ b;

证明:

a b a = a ^ b b = a ^ b a = a ^ b

0 0 a=0 b=0 a=0 b=0 a=0 b=0

0 1 a=1 b=1 a=1 b=0 a=1 b=0

1 0 a=1 b=0 a=1 b=1 a=0 b=1

1 1 a=0 b=1 a=0 b=1 a=1 b=1

5. << 按位左移

a << n 双目运算符 结合性 从左至右 "把a按bit位 整体左移n位"

  • 高位左移后 直接丢弃 低位空出来的n位 直接补0
  • 如果丢弃的高位都是0的话 那么左移n位 就表示 乘以 2的n次方
1 << 4 含义 • 1 是int 类型字面量,二进制:00000001(以常见 32 位 int 为例) • << 左移运算符,整体左移 4 位,低位补 0 1 → 二进制 00000001 1 << 4 → 二进制 00010000,十进制 16

练习:

1.构造一个整数(32bits) bit7 和 bit5 为 1 其他bit位 为0 该如何构造

(1 << 5) | (1 << 7)

6. >> 按位右移

x >> n 双目运算符 结合性 从左至右 "把a按bit位整体 右移 n位"

  • 低位右移 直接丢弃 高位补什么
  • 对于无符号数 高位补0
  • 对于有符号数 高位补 符号位

练习:

分析如下程序的输出结果 #include <stdio.h> int main() { int a = -1; a = a >> 31; printf("%d\n",a);// -1 printf("%u\n",a);// 2^32 -1 unsigned int b = -1; b = b >> 31; printf("%d\n",b);//1 printf("%u\n",b);//1 }

7.掩码(mask)

  • 掩码是一种位模式
  • 掩码中为1的bit位 表示我们要选取的bit位集合
  • 通俗来讲 就是表示你对哪些bit位感兴趣

如:

我们要选取 bit0 和 bit1 那么 掩码 0x3

00000000 00000000 00000000 0000 0011

如果 mask = 0xFF 表示我要选取 低八位

00000000 00000000 00000000 1111 1111

例子:

1.假设有一个整型变量 x = 0x345678AB 我要选取x的低八位

低八位的掩码 0xFF

x & ( (1<<8)-1 ) ==> 0xAB

2.假设有一个整型变量x 我想要选取x中的 bit5开始的4个bit位(往高位走) 该如何操作 mask: 00000000 00000000 0000 0001 1110 0000 mask: ( (1<<4) - 1) << 5 注: ( (1<<4) -1 ) : 0xF x & mask xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx & 00000000 00000000 00000001 11100000 00000000 00000000 0000000x xxx00000 --> ( x & ( 0xF << 5 ) ) ( x & ( 0xF << 5 ) ) >> 5

8.总结

清0 : &0

置1 : |1

取反 : ^1

3.5 赋值运算符

a = b 双目运算符 结合性 "从右往左" 把表达式b的值 赋值给 a

赋值运算符的优先级 排倒数第二 倒数第一是逗号运算符

a = b

把表达式b的值 赋值给a(把这个值b写入到a的地址中去a需要具备一个可写的地址(左值) "变量"

赋值符号左边的操作数必须为"可写的地址"

例子

5 = 5 //error 5 == 5 //ok 2 + 3 = 5;//2 + 3 表达式 不具备左值 int x = 2,y = 3; x + y = 5;//error x + y也是表达式 x = 5;//ok x++ = 6; /* 4-赋值运算符.c: In function ‘main’: // 赋值操作的左边需要是一个左值 4-赋值运算符.c:6:9: error: lvalue required as left operand of assignment 6 | x++ = 6; | ^ */

赋值表达式:由赋值运算符连接操作数的式子 称为 赋值表达式

赋值表达式的值:就是赋值完之后 左边那个操作数的值

y = x = 3;

==>

y = (x = 3); //x = 3 是一个赋值表达式这个表达式的值 就是 x的值

把赋值表达式 x = 3 的值 赋值给 y

复合的赋值运算符:赋值运算符可以和算术运算符、位运算符组成复合的赋值运算符

+= -= *= /= %=

>>= <<= |= &= ^=

a += b;//===> a = a + b;

a <<= 2;// ===> a = a << 2;

3.6 条件运算符

? : 三目运算符

expression ? a : b

  • 先判断 expression 的值 如果它的值为真(非0) 则整个表达式的值为 a
  • 如果它的值为假(0) 则整个表达式的值为 b
    if(a > b) { x = 250; } else { x = 360; } x = (a>b?250:360); 或 a>b?(x = 250):(x = 360);

3.7 逗号运算符

a,b 双目运算符 结合性 从左至右 优先级最低

先计算表达式a的值 然后再算 表达式b的值整个逗号表达式的值就是最右边那个表达式的

表达式1,表达式2

例子

a = (3,2) //a的值为 2

这是把表达式 (3,2) 的值 赋值为 a

a = 3,a = 2

a = 3,a = 2,a = 4

=> (a = 3,a = 2),a = 4

逗号表达式的形式可以是下面这样的

表达式1,表达式2,表达式3, …. , 表达式n

  • 求值顺序:先算表达式1 再算表达式2 再算表达式3 …. 最后算表达式n的值
  • 整个逗号表达式的值 就是最右边那个表达式的值

分析如下程序的结果

int main() { int a,b,c,d; int e = (a = 5,b = 6,c = 7,d = 8); printf("%d %d %d %d %d\n",a,b,c,d,e);//5 6 7 8 8 }

3.8 指针运算符

* 指向运算符

& 取地址运算符

3.9 求字节运算符

sizeof()

int a[10];//数组名为a 数组元素个数10个 a[0] ~ a[9] 数组元素的类型 int

sizeof(a[0]): 4 bytes

sizeof(a) : 40 bytes

3.10 分量运算符

.

->

3.11 下标运算符

[]

如:

取数组的元素

a[0]

a[1]

....

3.12 强制类型转换

(类型)表达式=

(int)3.5

(int)(3.2+4.9) ==> 8

(int)3.2 + 4.9 ==> 7.9

4.运算符的优先级和结合性

运算符结合性
() [] -> .从左至右
! ~ ++ -- +(正号) -(负号) *(指向) &(取地址符) sizeof从右至左
*(乘) /(除) %从左至右
+(加) -(减)从左至右
<< >>从左至右
< <= > >=从左至右
== !=从左至右
& 按位与从左至右
^ 按位异或从左至右
| 按位或从左至右
&&从左至右
||从左至右
?:从右至左
= += -= *= /= %= &=从右至左
^= |= <<= >>=从右至左
,从左至右
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/14 4:49:20

工业信号采集:FOD4216光耦与PIC18F25J11的抗干扰方案

1. 工业信号采集的挑战与核心需求在电机控制、PLC系统、工业自动化等场景中&#xff0c;信号采集的准确性直接关系到整个系统的可靠性。我曾参与过一个纺织机械控制项目&#xff0c;车间里数十台大功率电机同时运转时&#xff0c;控制板接收到的传感器信号会出现明显的毛刺和偏…

作者头像 李华
网站建设 2026/7/14 4:48:54

HybridCLR热更新开发中UnityLinker.exe报错的系统性排查与解决方案

1. 项目概述&#xff1a;当HybridCLR的Generate All命令撞上UnityLinker.exe如果你正在使用HybridCLR为你的Unity项目构建热更新能力&#xff0c;那么“Generate All”这个命令对你来说一定不陌生。它是整个热更新工作流中至关重要的一步&#xff0c;负责生成桥接AOT&#xff0…

作者头像 李华
网站建设 2026/7/14 4:48:30

施工企业合同管控工具测评:蓝燕云全生命周期管理能力

工程合同的管理周期通常跨越数月甚至数年&#xff0c;从签订到最终结算&#xff0c;中间经历签证变更、分阶段结算、付款收款等多个环节。一份合同能否管清楚&#xff0c;关键看从签约到结算的全过程是否有完整记录、各环节数据是否可追溯。传统方式下&#xff0c;合同文本锁在…

作者头像 李华
网站建设 2026/7/14 4:47:29

Visual C++控制台编程实战:CmdTool工具包设计与实现

1. 项目概述&#xff1a;为什么我们需要一个CmdTool工具包&#xff1f;如果你在Windows环境下用Visual C做过控制台程序&#xff0c;大概率经历过这样的场景&#xff1a;想解析一下命令行参数&#xff0c;得自己写argc和argv的循环&#xff1b;想给输出加点颜色&#xff0c;得去…

作者头像 李华
网站建设 2026/7/14 4:46:17

C#贪吃蛇实战:从零到8KB的零分配与Native AOT优化

1. 项目概述&#xff1a;为什么贪吃蛇是C#学习的“四部曲核心”&#xff1f;如果你正在学习C#&#xff0c;或者想检验自己C#基础是否扎实&#xff0c;那么亲手写一个贪吃蛇游戏&#xff0c;绝对是一个绕不开的“里程碑式”实践项目。这听起来可能有点老套&#xff0c;毕竟贪吃蛇…

作者头像 李华
网站建设 2026/7/14 4:45:52

爬虫监控与告警系统——成功率/延迟/异常监控与Prometheus+Grafana实战

文章目录 每日一句正能量 一、引言:为什么爬虫系统需要专业监控? 二、监控体系整体架构 2.1 架构设计原则 2.2 整体架构图 三、Prometheus指标设计与采集 3.1 爬虫业务指标定义 3.2 指标采集配置 3.3 指标命名与标签最佳实践 四、Grafana监控仪表盘实战 4.1 成功率与延迟分析…

作者头像 李华