01. 常用的运算符分类
运算符类型 | 作用 |
---|---|
算术运算符 | 用于处理四则运算 |
赋值运算符 | 用于将表达式的值赋给变量 |
比较运算符 | 用于表达式的比较,并返回一个真值或假值 |
逻辑运算符 | 用于根据表达式的值返回真值或假值 |
位运算符 | 用于处理数据的位运算 |
sizeof运算符 | 用于求字节数长度 |
02. 算数运算符
运算符 | 术语 | 示例 | 结果 |
---|---|---|---|
+ | 正号 | +3 | 3 |
- | 负号 | -3 | -3 |
+ | 加 | 10 + 5 | 15 |
- | 减 | 10 - 5 | 5 |
* | 乘 | 10 * 5 | 50 |
/ | 除 | 10 / 5 | 2 |
% | 取模(取余) | 10 % 3 | 1 |
++ | 前自增 | a=2; b=++a; | a=3; b=3; |
++ | 后自增 | a=2; b=a++; | a=3; b=2; |
– | 前自减 | a=2; b=–a; | a=1; b=1; |
– | 后自减 | a=2; b=a–; | a=1; b=2; |
#include <stdio.h>
int main()
{
int a = 5;
int b = 2;
double c = a/b;
printf("c = %lf\n",c); //打印结果: 2.000000 不是我们想要的
//两个数相除,想要得到小数,除数或被除数必须有一个是浮点数,否则会取整
int d = a % b; //a = 5, b = 2;
printf("d = %d\n",&d); //打印结果1
//后置++,先用后加,先执行完这个语句,a的值赋值给d,a再自加1
d = a++;
printf("d = %d\n",&d); //打印结果5
//前置++,先加后用,a先自加1,再执行这个语句,将a的结果赋值给d
d = 1;
a = 5;
d = ++a;
printf("d = %d\n",&d); //打印结果6
return 0;
}
03. 赋值运算符
运算符 | 术语 | 示例 | 结果 |
---|---|---|---|
= | 赋值 | a=2; b=3; | a=2; b=3; |
+= | 加等于 | a=0; a+=2; | a=2; |
-= | 减等于 | a=5; a-=3; | a=2; |
*= | 乘等于 | a=2; a*=2; | a=4; |
/= | 除等于 | a=4; a/=2; | a=2; |
%= | 模等于 | a=3; a%2; | a=1; |
#include <stdio.h>
int main()
{
int a = 2;
a += 2; //a加上2后,在赋值给a,相当于 a = a + 2;
//后面的类似
return 0;
}
04. 比较运算符
运算符 | 术语 | 示例 | 结果 |
---|---|---|---|
== | 相等于 | 4 == 3 | 0 |
!= | 不等于 | 4 != 3 | 1 |
< | 小于 | 4 < 3 | 0 |
> | 大于 | 4 > 3 | 1 |
<= | 小于等于 | 4 <= 3 | 0 |
>= | 大于等于 | 4 >= 1 | 1 |
非0的数就是真,通常以1表示真
0就是假,以0表示假
#include <stdio.h>
int main()
{
//因为 4 == 3为假, 所以结果为0
printf("%d\n",4 == 3);
//因为 4 > 3为真, 所以结果为1
printf("%d\n",4 > 3);
//因为 4 != 3为真,所以结果为1,
printf("%d\n",4 != 3);
return 0;
}
05. 逻辑运算符
运算符 | 术语 | 示例 | 结果 |
---|---|---|---|
! | 非 | !a | 如果a为假,则!a为真; 如果a为真,则!a为假。 |
&& | 与 | a && b | 如果a和b都为真,则结果为真,否则为假。 |
|| | 或 | a || b | 如果a和b有一个为真,则结果为真,二者都为假时,结果为假。 |
#include <stdio.h>
int main()
{
//因为4 == 3为假,所以!(4==3)为真,结果是1
printf("%d\n",4 == 3);
//&&,左右结果都是真,整体结果就为真
printf("%d\n",1 && 0); //结果是:0
//||,只要有一边是真,结果就是真
printf("%d\n",1 || 0); //结果是:1
return 0;
}
短路规则(编译器优化)
||运算符:左边为真,右边不执行
&&运算符:左边为假,右边不执行
06. 位逻辑运算符
按位取反 ~
一元运算符~,将每一位的1变为0,将0变为1
~(10011010)
01100101
假设a是一个unsigned char,已赋值为2.在二进制中,2是00000010.于是-a的值为11111101或者253。请注意该运算符不会改变a的值,a仍为2。
unsigned char a = 2; //00000010
unsigned char b = ~a; //11111101
printf("ret = %d\n", a); //ret = 2
printf("ret = %d\n", b); //ret = 253
按位与 &
二元运算符&。对于每个位,只有两个操作数的对应位都是1时结果才为1。(都为1才是1,有一个是0结果为0)
(10010011)
& (00111101)
= (00010001)
C也有一个组合的位与-赋值运算符:&=。下面两个将产生相同的结果:
val &= 0377
val = val & 0377
按位或 |
二元运算符|。对于每个位,如果其中任意操作数中对应的位为1,那么结果位就为1。(有一个为1结果就是1,都为0才是0)
(10010011)
| (00111101)
= (10111111)
C也有组合位或-赋值运算符: |=
val |= 0377
val = val | 0377
按位异或 ^
二元运算符^。对于每个位,如果操作数中的对应位数字一样(都是1或者都是0),则结果为0,反之,作数中的对应位数字不一样,结果为1(相异为1)
(10010011)
^ (00111101)
= (10101110)
C也有一个组合的位异或-赋值运算符: ^=
val ^= 0377
val = val ^ 0377
用法
打开位
一、10011010 的第二位 置1
(10011010)
| (00000100)
= (10011110)
二、10011010 全部位 置1
(10011010)
| (01100101)
= (11111111)
关闭位
10011010 全部位 置0
(10011010)
& (01100101)
= (00000000)
转置位
10010011 ^ 0xff 取反
(10010011)
^ (11111111)
= (01101100)
交换两个数
a = a ^ b
b = a ^ b
a = a ^ b
07. 移位运算符
左移 <<
左移运算符<<将其左侧操作数的值的每位向左移动,移动的位数由其右侧操作数指定。空出来的位用0填充,并且丢弃移出左侧操作数末端的位。在下面例子中,每位向左移动两个位置
(10001010) << 2
↓
(00101000)
左移一位相当于 原值*2
1 << 1 = 2;
2 << 1 = 4;
4 << 1 = 8;
8 << 2 = 32
右移 >>
右移运算符>>将其左侧的操作数的值每位向右移动,移动的位数由其右侧的操作数指定。丢弃移出左侧操作数有段的位。对于unsigned类型,使用0填充左端空出的位。对于有符号类型,结果依赖于机器。空出的位可能用0填充,或者使用符号(最左端)位的副本填充。
//有符号值
(10001010) >> 2
(00100010) //在某些系统上的结果值
(10001010) >> 2
(11100010) //在另一些系统上的结果
//无符号值
(10001010) >> 2
(00100010) //所有系统上的结果值
用法
移位运算符能够提供快捷、高效(依赖于硬件)对2的幂的乘法和除法。
number << n | number乘以2的n次幂 |
---|---|
number >> n | 如果number非负,则用number除以2的n次幂 |
08. 运算符优先级
优先级 | 运算符 | 结合方向 |
---|---|---|
1 | [] () . -> | 左到右 |
2 | - ~ ++ – * & ! (类型) sizeof | 右到左 |
3 | / * % | 左到右 |
4 | + - | 左到右 |
5 | << >> | 左到右 |
6 | > >= < <= | 左到右 |
7 | == != | 左到右 |
8 | & | 左到右 |
9 | ^ | 左到右 |
10 | | | 左到右 |
11 | && | 左到右 |
12 | || | 左到右 |
13 | ? : | 右到左 |
14 | 赋值运算符 | 右到左 |
15 | , 逗号运算符 | 左到右 |
09. 类型转换
#include <stdio.h>
int main()
{
//隐式转换
double a;
int b = 10;
//字节小的类型转字节大的类型,隐式转换,编译器自动转换
//b自动转换成double型,再给a赋值
a = b;
//强制转换
double a = 10;
a = (int)a; //将a强制转换为int型
int i = 0;
//%u打印,所以它需要一个unsigned int型,将i进行强转成unsigned int型
printf(" %u \n",(unsigned int)i);
return 0;
}
强制类型转换原则:占用内存字节少的类型,向占用内存字节数多的类型转换,保证精度不降低。