运算符是一种特殊的符号,用以用于数据的运算、赋值和比较等。
表达式指的是一组运算数、运算符的组合,表达式一定具有值,一个变量或一个常量就是一个表达式,变量、常量与运算符也可以组成复杂一些的表达式。
一:运算符分类
(1)按照操作数个数分类:
- 一元运算符(一目运算符)
- 二元运算符(二目运算符)
- 三元运算符(三目运算符)
(2) 按照功能分类:
- 算术运算符
- 赋值运算符
- 关系运算符
- 逻辑运算符
- 位运算符
二:算术运算符
算术运算符是对数值类型的变量进行运算的,在C程序中使用的非常多。
运算符 |
描述 |
操作数个数 |
组成的表达式的值 |
副作用 |
+ |
正号 |
1 |
操作数本身 |
无 |
- |
负号 |
1 |
操作数符号取反 |
无 |
+ |
加号 |
2 |
两个操作数之和 |
无 |
- |
减号 |
2 |
两个操作数之差 |
无 |
* |
乘号 |
2 |
两个操作数之积 |
无 |
/ |
除号 |
2 |
两个操作数之商 |
无 |
% |
取模(取余) |
2 |
两个操作数相除的余数 |
无 |
++ |
自增 |
1 |
操作数自增前或自增后的值 |
有 |
- - |
自减 |
1 |
操作数自减前或自减后的值 |
有 |
//正号和负号
#include <stdio.h>
int main()
{
int x = 12;
int x1 = -x, x2 = +x;
int y = -67;
int y1 = -y, y2 = +y;
printf("x1=%d, x2=%d \n", x1, x2);
printf("y1=%d, y2=%d \n", y1, y2);
return 0;
}
//加、减、乘、除
#include <stdio.h>
int main()
{
int a = 5 + 2.5;
printf("%d\n", a * a);
double b = 6 / 4;
printf("%f\n", b); // 输出 1.000000
double c = 6.0 / 4;
printf("%f\n", c); // 输出 1.500000
return 0;
}
注意:整数之间做除法时,结果只保留整数部分而舍弃小数部分。
//取模(取余)
#include <stdio.h>
int main()
{
int res1 = 10 % 3;
printf("%d\n", res1);
int res2 = -10 % 3;
printf("%d\n", res2);
int res3 = 10 % -3;
printf("%d\n", res3);
int res4 = -10 % -3;
printf("%d\n", res4);
return 0;
}
注意:运算结果的符号与被模数也就是第一个操作数相同。
自增和自减
- 自增、自减运算符可以写在操作数的前面也可以写在操作数后面,不论前面还是后面,对操作数的副作用是一致的。
- 自增、自减运算符在前在后,对于表达式的值是不同的。 如果运算符在前,表达式的值是操作数自增、自减之后的值;如果运算符在后,表达式的值是操作数自增、自减之前的值。
//自增和自减
#include <stdio.h>
int main()
{
int i1 = 10, i2 = 20;
int i = i1++;
printf("%d\n", i); // 10
printf("%d\n", i1); // 11
i = ++i1;
printf("%d\n", i); // 12
printf("%d\n", i1); // 12
i = i2--;
printf("%d\n", i); // 20
printf("%d\n", i2); // 19
i = --i2;
printf("%d\n", i); // 18
printf("%d\n", i2); // 18
return 0;
}
三:关系运算符(比较运算符)
运算符 |
描述 |
操作数个数 |
表达式的值 |
副作用 |
== |
相等 |
2 |
0 或 1 |
无 |
!= |
不等 |
2 |
0 或 1 |
无 |
< |
小于 |
2 |
0 或 1 |
无 |
> |
大于 |
2 |
0 或 1 |
无 |
<= |
小于等于 |
2 |
0 或 1 |
无 |
>= |
大于等于 |
2 |
0 或 1 |
无 |
#include <stdio.h>
int main()
{
int a = 8;
int b = 7;
printf("a>b的值:%d \n", a > b);
printf("a>=b的值:%d \n", a >= b);
printf("a<b的值:%d \n", a < b);
printf("a<=b的值:%d \n", a <= b);
printf("a==b的值:%d \n", a == b);
printf("a!=b的值:%d \n", a != b);
return 0;;
}
四:逻辑运算符
运算符 |
描述 |
操作数个数 |
表达式的值 |
副作用 |
&& |
逻辑与 |
2 |
0 或 1 |
无 |
|| |
逻辑或 |
2 |
0 或 1 |
无 |
! |
逻辑非 |
1 |
0 或 1 |
无 |
(1):逻辑与 &&
如果两个操作数都为真(非零),那么表达式的值为真,否则为假。
如果第一个操作数为假,第二个操作数没有计算的必要了,这种现象称为短路现象。
#include <stdio.h>
int main()
{
double score = 70; // 成绩
if (score >= 60 && score <= 80)
{
printf("ok1 \n");
}
else
{
printf("ok2 \n");
}
int a = 10, b = 99;
// 短路现象
if (a < 2 && ++b > 99)
{
printf("ok100");
}
printf("b=%d\n", b);
return 0;
}
(2):逻辑或 ||
只要有一个操作数为真,表达式的值就为真;两个操作数都为假,表达式的值为假。
如果第一个操作数为真,第二个操作数没有计算的必要了,这种现象称为短路现象。
#include <stdio.h>
int main()
{
double score = 70;
if (score >= 70 || score <= 80)
{
printf("ok1 \n");
}
else
{
printf("ok2 \n");
}
int a = 10, b = 99;
// 短路现象
if (a > 5 || b++ > 100)
{ //
printf("ok100 \n");
}
printf("b=%d\n", b);
return 0;
}
(3):逻辑非
操作数状态取反作为表达式的值。
#include <stdio.h>
int main()
{
int score = 100;
int res = score > 99;
if (res)
{
printf("hello, tom \n");
}
if (!res)
{
printf("hello,jack \n");
}
return 0;
}
五:赋值运算符
运算符 |
描述 |
操作数个数 |
表达式的值 |
副作用 |
= |
赋值 |
2 |
左边操作数的值 |
有 |
+= |
相加赋值 |
2 |
左边操作数的值 |
有 |
-= |
相减赋值 |
2 |
左边操作数的值 |
有 |
*= |
相乘赋值 |
2 |
左边操作数的值 |
有 |
/= |
相除赋值 |
2 |
左边操作数的值 |
有 |
%= |
取余赋值 |
2 |
左边操作数的值 |
有 |
<<= |
左移赋值 |
2 |
左边操作数的值 |
有 |
>>= |
右移赋值 |
2 |
左边操作数的值 |
有 |
&= |
按位与赋值 |
2 |
左边操作数的值 |
有 |
^= |
按位异或赋值 |
2 |
左边操作数的值 |
有 |
|= |
按位或赋值 |
2 |
左边操作数的值 |
有 |
- 赋值运算符的第一个操作数(左值)必须是变量的形式,第二个操作数可以是任何形式的表达式。
- 赋值运算符的副作用针对第一个操作数。
#include <stdio.h>
int main()
{
int a = 10, b = 20, c = 30;
c += 3; // 等价于 c = c + 3; 计算后c的值变为33
c += b; // 等价于 c = c + b; 计算后c的值变为53
a += 1.7; // 等价于 a = a + 1.7 计算后a的值变为11
printf("a=%d b=%d c=%d", a, b, c);
return 0;
}
六:位运算符
运算符 |
描述 |
操作数个数 |
副作用 |
& |
按位与 |
2 |
无 |
| |
按位或 |
2 |
无 |
^ |
按位异或 |
2 |
无 |
~ |
按位取反 |
1 |
无 |
<< |
按位左移 |
2 |
无 |
>> |
按位右移 |
2 |
无 |
注意:操作数进行位运算的时候,以它的补码形式进行运算。
(1):按位与、按位或、按位异或
#include <stdio.h>
int main()
{
int a = 17;
int b = -12;
printf("a&b=%d\n", a & b); // a&b=16
printf("a|b=%d\n", a | b); // a|b=-11
printf("a^b=%d\n", a ^ b); // a^b=-27
return 0;
}
(2):按位取反
#include <stdio.h>
int main()
{
int a = 17;
int b = -12;
// 按位非
printf("~a=%d\n", ~a);
printf("~b=%d\n", ~b);
return 0;
}
(3):按位左移、按位右移
#include <stdio.h>
int main()
{
int a = 17;
int b = -12;
// 按位左移
printf("a<<2=%d\n", a << 2); // a<<2=68
printf("b<<2=%d\n", b << 2); // b<<2=-48
// 按位右移
printf("a>>3=%d\n", a >> 3); // a>>3=2
printf("b>>3=%d\n", b >> 3); // b>>3=-2
return 0;
}
七:三元运算符
基本语法:
条件表达式? 表达式1: 表达式2;
如果条件表达式为非0(真),整个表达式的值是表达式1;
如果条件表达式为0(假),整个表达式的值是表达式2;
#include <stdio.h>
int main()
{
int a = 10;
int b = 99;
int res = a > b ? a++ : b--;
int n1 = a > b ? 1.1 : 1.2;
printf("a=%d \n", a);
printf("b=%d \n", b);
printf("res=%d \n", res);
return 0;
}
- 计算两个数的最大值(a , b)
#include <stdio.h>
int main()
{
int a = 10;
int b = 100;
int max = a > b ? a : b;
printf("a和b中最大的数字:%d", max);
return 0;
}
2.计算三个数的最大值
#include <stdio.h>
int main()
{
int a = 10;
int b = 100;
int c = 199;
// int max1 = a>b ? a : b;
// int max2 = max1>c ? max1:c;
int max = (a > b ? a : b) > c ? (a > b ? a : b) : c;
printf("a、b、c中最大的数字:%d", max);
return 0;
}
八:运算符优先级
优先级 |
运算符 |
名称或含义 |
结合方向 |
1 |
[] |
数组下标 |
左到右 |
() |
圆括号 | ||
. |
成员选择(对象) | ||
-> |
成员选择(指针) | ||
2 |
- |
负号运算符 |
右到左 |
(类型) |
强制类型转换 | ||
++ |
自增运算符 | ||
-- |
自减运算符 | ||
* |
取值运算符 | ||
& |
取地址运算符 | ||
! |
逻辑非运算符 | ||
~ |
按位取反运算符 | ||
sizeof |
长度运算符 | ||
3 |
/ |
除 |
左到右 |
* |
乘 | ||
% |
余数(取模) | ||
4 |
+ |
加 |
左到右 |
- |
减 | ||
5 |
<< |
左移 |
左到右 |
>> |
右移 | ||
6 |
> |
大于 |
左到右 |
>= |
大于等于 | ||
< |
小于 | ||
<= |
小于等于 | ||
7 |
== |
等于 |
左到右 |
!= |
不等于 | ||
8 |
& |
按位与 |
左到右 |
9 |
^ |
按位异或 |
左到右 |
10 |
| |
按位或 |
左到右 |
11 |
&& |
逻辑与 |
左到右 |
12 |
|| |
逻辑或 |
左到右 |
13 |
?: |
条件运算符 |
右到左 |
14 |
= |
赋值运算符 |
右到左 |
/= |
除后赋值 | ||
*= |
乘后赋值 | ||
%= |
取模后赋值 | ||
+= |
加后赋值 | ||
-= |
减后赋值 | ||
<<= |
左移后赋值 | ||
>>= |
右移后赋值 | ||
&= |
按位与后赋值 | ||
^= |
按位异或后赋值 | ||
|= |
按位或后赋值 | ||
15 |
, |
逗号运算符 |
左到右 |
总结:
- 不要过多的依赖运算的优先级来控制表达式的执行顺序,这样可读性太差,尽量使用小括号来控制表达式的执行顺序。
- 不要把一个表达式写得过于复杂,如果一个表达式过于复杂,则把它分成几步来完成。
- 运算符优先级不用刻意地去记忆,总体上:一元运算符 > 算术运算符 > 关系运算符 > 逻辑运算符 > 三元运算符 > 赋值运算符。
本章的内容就到这里。
关注我一起成为嵌入式大佬。